1

I am just playing around trying to get a simple 3 slide slider working but run into some issues with the javascript. All i want to happen is on click of the slider colour i would like the current slider to slide out and the selected one to slide in. I am trying to do it by adding an active class to the slider number that I have clicked to show. I just cant quite work out where I have gone wrong. I don't want to use jQuery as I am trying to learn vanilla javascript.

Thanks as always

window.onload = onPageLoad();

function onPageLoad() {
  document.querySelector('.red').classList.add('active');
};

document.querySelector('.box').addEventListener('click', function() {
  document.querySelector('.red').classList.toggle('active');
  document.querySelector('.green').classList.toggle('active');
  document.querySelector('.yellow').classList.toggle('active');


});
* {
  padding: 0;
  margin: 0;
}

.main__wrapper {
  position: relative;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}

.red,
.green,
.yellow {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  transform: translateX(-100%);
  transition: transform 1.2s;
}

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.yellow {
  background-color: yellow;
}

.active {
  transform: translateX(0) !important;
  transition: transform 1s !important;
}

.slide__select {
  position: absolute;
  bottom: 0;
  right: 0;
  width: 60%;
  height: 20%;
  z-index: 10;
  display: flex;
}

.box {
  position: relative;
  flex: 1 0 0;
  color: $color-white;
  display: flex;
  align-items: center;
  cursor: pointer;
  background-color: #A68D71;
}

.box span {
  display: block;
  position: relative;
  z-index: 11;
}

.box::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  background-color: yellow;
  width: 100%;
  height: 0;
  transition: height .3s;
}

.box:hover::after {
  height: 100%;
  transition: height .3s;
}
<div class="main__wrapper">

  <section class="red">

  </section>

  <section class="green">

  </section>

  <section class="yellow">

  </section>

  <div class="slide__select">
    <div class="box">
      <span>red</span>
    </div>
    <div class="box">
      <span>green</span>
    </div>
    <div class="box">
      <span>yellow</span>
    </div>
  </div>

</div>

1
  • 1
    You are toggling all three sections at the same time. Toggle simply reverses their state. What you want to do it remove active from all of them, and add active to the selected one. Commented Apr 16, 2018 at 20:45

4 Answers 4

4

You're only adding an event listener to the first box and you're toggling every box's active class in order, and the last one is yellow, so you result with a yellow background.

querySelector returns the first DOM element it finds, which is the red box.

For the functionality that you want, you have to add event listeners to each box (querySelectorAll)

Sign up to request clarification or add additional context in comments.

4 Comments

Even if he used selectAll it would toggle all of them the same way.
Ya, he'll have to update the way he's toggling the classes
It's not too difficult, but my answer is just to explain why there's this wonky functionality.
Thanks very much for this, I can clearly see where I have gone wrong now. I actually managed to get this to work quite well using radio buttons and putting a label on each box then using the :checked pseudo class to move the box with transform translate. Seemed to do the trick but was looking to use JavaScript as that’s what I’m trying to learn at the moment
2

window.onload = onPageLoad();

function onPageLoad() {
  document.querySelector('.red').classList.add('active');
};

document.querySelector('.redbox').addEventListener('click', function() {
  document.querySelector('.red').classList.add('active');
  document.querySelector('.green').classList.remove('active');
  document.querySelector('.yellow').classList.remove('active');
});
document.querySelector('.greenbox').addEventListener('click', function() {
  document.querySelector('.red').classList.remove('active');
  document.querySelector('.green').classList.add('active');
  document.querySelector('.yellow').classList.remove('active');
});
document.querySelector('.yellowbox').addEventListener('click', function() {
  document.querySelector('.red').classList.remove('active');
  document.querySelector('.green').classList.remove('active');
  document.querySelector('.yellow').classList.add('active');
});
* {
  padding: 0;
  margin: 0;
}

.main__wrapper {
  position: relative;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}

.red,
.green,
.yellow {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  transform: translateX(-100%);
  transition: transform 1.2s;
}

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.yellow {
  background-color: yellow;
}

.active {
  transform: translateX(0) !important;
  transition: transform 1s !important;
}

.slide__select {
  position: absolute;
  bottom: 0;
  right: 0;
  width: 60%;
  height: 20%;
  z-index: 10;
  display: flex;
}

.box {
  position: relative;
  flex: 1 0 0;
  color: $color-white;
  display: flex;
  align-items: center;
  cursor: pointer;
  background-color: #A68D71;
}

.box span {
  display: block;
  position: relative;
  z-index: 11;
}

.box::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  background-color: yellow;
  width: 100%;
  height: 0;
  transition: height .3s;
}

.box:hover::after {
  height: 100%;
  transition: height .3s;
}
<div class="main__wrapper">

  <section class="red">

  </section>

  <section class="green">

  </section>

  <section class="yellow">

  </section>

  <div class="slide__select">
    <div class="redbox box">
      <span>red</span>
    </div>
    <div class="greenbox box">
      <span>green</span>
    </div>
    <div class="yellowbox box">
      <span>yellow</span>
    </div>
  </div>

</div>

Here is a primitive example solution. It's overly verbose but shows you what is needed. This can be condensed.

To get an idea of how it can be condensed, all three listeners CAN be condensed into a single listener how you had it, listen just to the .box selector. But if you do that, you need a way to identify which box was clicked. This can be done via a data attribute or by looking at the html text. A data attribute would be my preferred method, as it separates the content from the logic a bit, but either would work.

Comments

1

Another less verbose solution:

window.onload = onPageLoad();

function onPageLoad() {
  document.querySelector('.red').classList.add('active');
};

var boxes = document.querySelectorAll('.box');
for (var i = 0; i < boxes.length; i++) {
  boxes[i].addEventListener('click', toggleSections);
}

var colors = ['red', 'green', 'yellow'];

function toggleSections(ev) {
  var color = ev.currentTarget.innerText;
  for (var c = 0; c < colors.length; c++) {
    var colorElem = document.querySelector('.' + colors[c]);
    if (colors[c] != color) {
      colorElem.classList.remove('active');
    } else {
      colorElem.classList.add('active');
    }
  }
}
* {
  padding: 0;
  margin: 0;
}

.main__wrapper {
  position: relative;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}

.red,
.green,
.yellow {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  transform: translateX(-100%);
  transition: transform 1.2s;
}

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.yellow {
  background-color: yellow;
}

.active {
  transform: translateX(0) !important;
  transition: transform 1s !important;
}

.slide__select {
  position: absolute;
  bottom: 0;
  right: 0;
  width: 60%;
  height: 20%;
  z-index: 10;
  display: flex;
}

.box {
  position: relative;
  flex: 1 0 0;
  color: $color-white;
  display: flex;
  align-items: center;
  cursor: pointer;
  background-color: #A68D71;
}

.box span {
  display: block;
  position: relative;
  z-index: 11;
}

.box::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  background-color: yellow;
  width: 100%;
  height: 0;
  transition: height .3s;
}

.box:hover::after {
  height: 100%;
  transition: height .3s;
}
<div class="main__wrapper">

  <section class="red">

  </section>

  <section class="green">

  </section>

  <section class="yellow">

  </section>

  <div class="slide__select">
    <div class="box">
      <span>red</span>
    </div>
    <div class="box">
      <span>green</span>
    </div>
    <div class="box">
      <span>yellow</span>
    </div>
  </div>

</div>

Comments

1

To achieve expected result, use below option

  1. Use one section to avoid looping of section elements

  2. Use querySelectorAll or elementsByClassName instead of querySelector to fetch all elements in array

  3. Use forEach to loop through all elements of class- box and add addEventListener and run another loop with forEach for span elements

  4. Use classList to add or remove

window.onload = onPageLoad();

function onPageLoad() {
  document.querySelector('.red').classList.add('active');
};

// use querySelectorAll to get all elements of class-box and forEach to loop through
document.querySelectorAll('.box').forEach(function(ele){
  //Add clici event through addEventListener
  ele.addEventListener('click', function() {
// use another querySelectorAll to get all elements of tag span and forEach to loop through
document.querySelectorAll('span').forEach(function(e){
  e.classList.remove('active');
  //use querySelector for section element and empty classList to remove active and red/green/yellow class names
  document.querySelector('section').className ='';
});
//toggle active class for clicked element
ele.children[0].classList.toggle("active");
//add active class for section
document.querySelector('section').classList.add('active');
//add class red/yellow/green using span innerHTML
document.querySelector('section').classList.add(ele.children[0].innerHTML);
 });
});
* {
  padding: 0;
  margin: 0;
}

.main__wrapper {
  position: relative;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}

.red,
.green,
.yellow {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  transform: translateX(-100%);
  transition: transform 1.2s;
}

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.yellow {
  background-color: yellow;
}

.active {
  transform: translateX(0) !important;
  transition: transform 1s !important;
}

.slide__select {
  position: absolute;
  bottom: 0;
  right: 0;
  width: 60%;
  height: 20%;
  z-index: 10;
  display: flex;
}

.box {
  position: relative;
  flex: 1 0 0;
  color: $color-white;
  display: flex;
  align-items: center;
  cursor: pointer;
  background-color: #A68D71;
}

.box span {
  display: block;
  position: relative;
  z-index: 11;
}

.box::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  background-color: yellow;
  width: 100%;
  height: 0;
  transition: height .3s;
}

.box:hover::after {
  height: 100%;
  transition: height .3s;
}
<div class="main__wrapper">

  <section class="red">

  </section>
  <div class="slide__select">
    <div class="box">
      <span>red</span>
    </div>
    <div class="box">
      <span>green</span>
    </div>
    <div class="box">
      <span>yellow</span>
    </div>
  </div>

</div>

code sample - https://codepen.io/nagasai/pen/vRoPwp

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.