Home > database >  Can I save a previous item conditionally in a forEach loop
Can I save a previous item conditionally in a forEach loop

Time:12-01

I am trying to make sort of sliding carousel that shows a different slide based on what the user has its mouse over. I am working with z-index to show the correct slide on top. But important is that the previous slide is underneath. So the idea is:

  1. All slides z-index: 1 by default
  2. If slide is shown, set z-index: 3
  3. When another slide is shown, set previous slide to z-index: 2 and the new one to 3

This was my work so far

slides = document.querySelectorAll('.slide');
navItems = document.querySelectorAll('.slider-navigation li');

navItems.forEach(navItem => {
  navItem.addEventListener('mouseover', () => onNavigationHover(navItem));
});

function onNavigationHover(navItem) {
  let slideKey = navItem.dataset.slide;

  slides.forEach((slide, index) => {
    if (slide.dataset.slide === slideKey) {
      slide.style.setProperty('--z-index', 3)
      // can i set the previous slide zIndex here to 2? 
      slide.classList.add('slideIn')
    } else {
      slide.style.setProperty('--z-index', 1)
      slide.classList.remove('slideIn')
    }
  });
}
img {
  z-index: var(--z-index);
  position: absolute;
  top: 0;
  left: 0;
  width: 200px;
  height: 150px;
  object-fit: cover;
}

div {
  height: 200px;
  width: 200px;
  position: relative;
}

img.slideIn {
  animation: slideIn 2s ease forwards;
}

@keyframes slideIn {
  from {
    translate: 200px;
  }
  to {
    translate: 0px;
  }
}
<ul class='slider-navigation'>
  <li data-slide='1'>Slide 1</li>
  <li data-slide='2'>Slide 2</li>
  <li data-slide='3'>Slide 3</li>
</ul>

<div>
  <img class='slide' data-slide='1' src='https://images.unsplash.com/photo-1669818319938-bb7029dc3fa3?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzfHx8ZW58MHx8fHw=&auto=format&fit=crop&w=500&q=60'>

  <img class='slide' data-slide='2' src='https://images.unsplash.com/photo-1669623313981-6af02eedb15c?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1fHx8ZW58MHx8fHw=&auto=format&fit=crop&w=500&q=60'>

  <img class='slide' data-slide='3' src='https://images.unsplash.com/photo-1446776811953-b23d57bd21aa?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTF8fHNwYWNlfGVufDB8fDB8fA==&auto=format&fit=crop&w=500&q=60' />
</div>

This is working great, except that the same image will always show underneath.

Is it possible to save the previous index and give it a different z-index? Or should I approach this in a different way? Thank you!

CodePudding user response:

One way to do this is using the .filter() method. You can use .filter() to find the current slide (by comparing the data attribute for slide) as well as grab the previous slide (by looking for any slide that has a z-index of 3 prior to any changes).

The steps for your onNavigationHover() function would then be:

  • Grab the previous top slide
  • Set the z-index of all slides to 1
  • Set the previous top slide (if it exists, as initially it won't) to a z-index of 2
  • Set the new top slide to a z-index of 3

slides = document.querySelectorAll('.slide');
navItems = document.querySelectorAll('.slider-navigation li');

navItems.forEach(navItem => {
  navItem.addEventListener('mouseover', () => onNavigationHover(navItem));
});

function onNavigationHover(navItem) {
  let prevSlide = Array.from(slides).filter(slide => getComputedStyle(slide).zIndex == 3)[0]
  
  slides.forEach(slide => {
    slide.style.setProperty('--z-index', 1)
    slide.classList.toggle('slideIn', slide.dataset.slide == navItem.dataset.slide)
  })
  prevSlide?.style.setProperty('--z-index', 2)
  Array.from(slides).filter(slide => slide.dataset.slide == navItem.dataset.slide)[0]?.style.setProperty('--z-index', 3)
}
img {
  z-index: var(--z-index);
  position: absolute;
  top: 0;
  left: 0;
  width: 200px;
  height: 150px;
  object-fit: cover;
}

div {
  height: 200px;
  width: 200px;
  position: relative;
}

img.slideIn {
  animation: slideIn 2s ease forwards;
}

@keyframes slideIn {
  from {
    translate: 200px;
  }
  to {
    translate: 0px;
  }
}
<div>
  <img class='slide' data-slide='1' width=200 src='https://images.unsplash.com/photo-1669818319938-bb7029dc3fa3?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzfHx8ZW58MHx8fHw=&auto=format&fit=crop&w=500&q=60'>

  <img class='slide' data-slide='2' width=200 src='https://images.unsplash.com/photo-1669623313981-6af02eedb15c?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1fHx8ZW58MHx8fHw=&auto=format&fit=crop&w=500&q=60'>
  
  <img class='slide' data-slide='3' width=200 src='https://images.unsplash.com/photo-1446776811953-b23d57bd21aa?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTF8fHNwYWNlfGVufDB8fDB8fA==&auto=format&fit=crop&w=500&q=60' />
</div>

<ul class='slider-navigation'>
  <li data-slide='1'>Slide 1</li>
  <li data-slide='2'>Slide 2</li>
  <li data-slide='3'>Slide 3</li>
</ul>

CodePudding user response:

You can either use JS directly as in the other answer that uses your updated example. Or based on your original post, add an attribute or even just an id to your DOM element like so

function onNavigationHover(navItem) {
  let slideKey = navItem.dataset.slide;

  slides.forEach((slide, index) => {
    if (slide.dataset.slide === slideKey) {
      slide.style.setProperty('--z-index', 3)
      // Set the index of the old element
      document.getElementById('active')?.style.setPropery('--z-index', 2);
      // Remove the id of the old element
      document.getElementById('active')?.removeAttribute('id');
      // Set the id on the current element
      slide.id = 'active';
    } else {
      slide.style.setProperty('--z-index', 1)
    }
  });
}

CodePudding user response:

Yes, it's possible. You can do it by holding the previous slide like this:

const slides = document.querySelectorAll('.slide');
const navItems = document.querySelectorAll('.slider-navigation li');
const previousSlide = null;

navItems.forEach(navItem => {
  navItem.addEventListener('mouseover', () => onNavigationHover(navItem));
});

function onNavigationHover(navItem) {
  let slideKey = navItem.dataset.slide;

  slides.forEach((slide, index) => {
    if (slide.dataset.slide === slideKey) {
      slide.style.setProperty('--z-index', 3);
      if(previousSlide && previousSlide !== slide) {
        previousSlide.style.setProperty('--z-index', 2);
      }
      previousSlide = slide;
      slide.classList.add('slideIn')
    } else if(slide !== previousSlide) {
      slide.style.setProperty('--z-index', 1)
      slide.classList.remove('slideIn')
    }
  });
}
  • Related