Tomas M
Tomas M

Reputation: 27

How can I make a reusable function?

I am trying to apply this function to multiple projects and I want to not repeat it. How can I do it in Vanilla JS? See the code below.

let slideIndex = 1;
showDivs(slideIndex);

function plusDivs(n) {
  showDivs(slideIndex += n);
}

function showDivs(n) {
  let i;
  let x = document.getElementsByClassName("slides");
  if (n > x.length) {
    slideIndex = 1
  }
  if (n < 1) {
    slideIndex = x.length
  }
  for (i = 0; i < x.length; i++) {
    x[i].style.display = "none";
  }
  x[slideIndex - 1].style.display = "block";
  document.getElementsByClassName("pagination")[0].innerText = slideIndex + ' / ' + x.length;
}
<div class="project1">
  <div class="pagination"></div>

  <div class="imgslide noselect">
    <div class="prev" onclick="plusDivs(-1)"></div>
    <div class="next" onclick="plusDivs(1)"></div>
    <img class="slides" src="img/project-1/Scan-4.jpg">
    <!-- <img class="slides" src="img/Scan-8.jpg"> -->
    <img class="slides" src="img/project-1/Scan-24.jpg">
    <img class="slides" src="img/project-1/Scan-35.jpg">
    <img class="slides" src="img/project-1/Scan-39.jpg">
    <img class="slides" src="img/project-1/Scan-40.jpg">
  </div>
</div>
<div class="project2">
  <div class="pagination"></div>

  <div class="imgslide noselect">
    <div class="prev" onclick="plusDivs(-1)"></div>
    <div class="next" onclick="plusDivs(1)"></div>
    <img class="slides" src="img/project-1/Scan-41.jpg">
    <!-- <img class="slides" src="img/Scan-8.jpg"> -->
    <img class="slides" src="img/project-1/Scan-22.jpg">
    <img class="slides" src="img/project-1/Scan-33.jpg">
    <img class="slides" src="img/project-1/Scan-38.jpg">
    <img class="slides" src="img/project-1/Scan-49.jpg">
  </div>
</div>

Divs with class project1 and project2 should be separated and the function simply changes image once clicked. I want to apply the same function for multiple projects without re-writing it every time.

Upvotes: 1

Views: 91

Answers (2)

Mark Schultheiss
Mark Schultheiss

Reputation: 34227

I see you have a good answer but I am adding this as an alternative.

I would suggest using a class for a more generic selector to the parent then use that. Note I also added the option here to set a predefined displayed image by using the data-slide-index attribute, then set that to the value of the currently selected image. If that were saved to a cookie for example, you could restore from that also.

You could remove the project1 and project2 classes if you wanted to.

I also used data-direction so that I could remove the click handler from the markup and not really care which button was clicked.

  • a bit cleaner markup without the event, making it more generic there without the group name need
  • restore the last viewed/first to view (with cookie addition or from back-end)
  • used a hidden class and toggled that for the show/hide
  • used a 0 based internally numbers as arrays are 0 based and makes coding simpler to maintain but added 1 for the display for normal people.
  • importantly, NO use of global variables

(function setup() {
  // add event listener to buttons
  let els = document.getElementsByClassName("project-container");
  for (let i = 0; i < els.length; i++) {
    let prevnext = els[i].getElementsByClassName("prevnext");
    for (let p = 0; p < prevnext.length; p++) {
      prevnext[p].addEventListener("click", plusMinusDivs, false);
    }
    //hide/show for each group, avoid this call by adding classes to markup
    showImage(els[i]);
  }
})();

function plusMinusDivs() {
  let parent = this.closest(".project-container");
  let slider = this.closest(".imgslide");
  let slideIndex = slider.dataset.slideIndex * 1;
  let nd = this.dataset.direction * 1;//*1 to avoid parse
  slideIndex = slideIndex += nd;
  let slides = parent.querySelectorAll(".slides");

  if (slideIndex >= slides.length) {
    slideIndex = 0;
  }
  if (slideIndex < 0) {
    slideIndex = slides.length - 1;
  }
  slider.dataset.slideIndex = slideIndex + "";
  showImage(parent);
}

function showImage(parent) {
  let slides = parent.querySelectorAll(".slides");
  let len = slides.length;
  for (let s = 0; s < len; s++) {
    slides[s].classList.toggle("hidden", true);
  }
  let slider = parent.querySelector(".imgslide");
  let slideIndex = slider.dataset.slideIndex * 1;//*1 to avoid parse
  slides[slideIndex].classList.toggle("hidden", false);
  let pageText = (slideIndex + 1) + ' / ' + len;
  parent.querySelector(".pagination").innerText = pageText;
}
.hidden {
  display: none;
}

.prevnext {
  background-color: #AAEEDD;
}
<div class="project-container project1">
  <div class="pagination">&nbsp;</div>
  <div class="imgslide noselect" data-slide-index="0">
    <button class="prevnext prev" data-direction="-1">&lt;&lt;</button>
    <button class="prevnext next" data-direction="1">&gt;&gt;</button>
    <img class="slides" src="img/project-1/Scan-4.jpg" alt="4" />
    <img class="slides" src="img/project-1/Scan-24.jpg" alt="24" />
    <img class="slides" src="img/project-1/Scan-35.jpg" alt="35" />
    <img class="slides" src="img/project-1/Scan-39.jpg" alt="39" />
    <img class="slides" src="img/project-1/Scan-40.jpg" alt="40" />
  </div>
</div>
<div class="project-container project2">
  <div class="pagination">&nbsp;</div>
  <div class="imgslide noselect" data-slide-index="3">
    <button class="prevnext prev" data-direction="-1">&lt;&lt;</button>
    <button class="prevnext next" data-direction="1">&gt;&gt;</button>
    <img class="slides" src="img/project-1/Scan-41.jpg" alt="2-41" />
    <img class="slides" src="img/project-1/Scan-22.jpg" alt="2-42" />
    <img class="slides" src="img/project-1/Scan-33.jpg" alt="2-33" />
    <img class="slides" src="img/project-1/Scan-38.jpg" alt="2-38" />
    <img class="slides" src="img/project-1/Scan-49.jpg" alt="2-49" />
  </div>
</div>

Upvotes: 0

Titus
Titus

Reputation: 22484

Instead of getting all the slides document.getElementsByClassName("slides") you should get the slides of the appropriate project document.getElementById("projectN").getElementsByClassName("slides"). You'll have to change both functions to accept another parameter for specifying the project.

let projectIndexes = {
  project1: 1,
  project2: 1
}
showDivs("project1", projectIndexes.project1);
showDivs("project2", projectIndexes.project2);

function plusDivs(project, n) {
  showDivs(project, projectIndexes[project] += n);
}

function showDivs(project, index) {
  let i;
  let x = document.getElementById(project).getElementsByClassName("slides");
  if (index > x.length) { index = 1 }
  if (index < 1) { index = x.length }
  for (i = 0; i < x.length; i++) {
      x[i].style.display = "none";
  }
  x[index - 1].style.display = "block";
  document.getElementById(project).getElementsByClassName("pagination")[0].innerText = index + ' / ' + x.length;
  projectIndexes[project] = index;
}
.slides {
  display: none;
}
<div id="project1">
    <div class="pagination"></div>

    <div class="imgslide noselect">
        <button class="prev" onclick="plusDivs('project1', -1)">Previous</button>
        <button class="next" onclick="plusDivs('project1', 1)">Next</button>
        <img class="slides" src="img/project-1/Scan-4.jpg" alt="project1 slide1">
        <img class="slides" src="img/project-1/Scan-24.jpg" alt="project1 slide2">
        <img class="slides" src="img/project-1/Scan-35.jpg" alt="project1 slide3">
        <img class="slides" src="img/project-1/Scan-39.jpg" alt="project1 slide4">
        <img class="slides" src="img/project-1/Scan-40.jpg" alt="project1 slide5">
    </div>
</div>
<br />
<div id="project2">
    <div class="pagination"></div>

    <div class="imgslide noselect">
        <button class="prev" onclick="plusDivs('project2', -1)">Previous</button>
        <button class="next" onclick="plusDivs('project2', 1)">Next</button>
        <img class="slides" src="img/project-1/Scan-41.jpg" alt="project2 slide1">
        <img class="slides" src="img/project-1/Scan-22.jpg" alt="project2 slide2">
        <img class="slides" src="img/project-1/Scan-33.jpg" alt="project2 slide3">
        <img class="slides" src="img/project-1/Scan-38.jpg" alt="project2 slide4">
        <img class="slides" src="img/project-1/Scan-49.jpg" alt="project2 slide5">
    </div>
</div>

Upvotes: 2

Related Questions