2

im trying to achieve something pretty simple. i have a list of items. if i click on one it should give it a class of selected. however if i click on another item in the list. it should remove the selected class from the previous element. this is my javascript code.

const timeRangeWrapper = document.querySelector('.time-range');
const timeOptions = timeRangeWrapper.querySelectorAll('.times .time-option');
    timeOptions.forEach((item, i) => {
        const domIndex = item.getAttribute('data-item');
        item.addEventListener('click', () => {
            if (i == domIndex) {
                item.classList.add('selected');
            } else if (i !== domIndex && item.classList.contains('selected')){
                item.classList.remove('selected');
            }
        });
    });

this is my markup

<div class="time-range">
    <span class="helper">Please select an exact booking time</span>
    <ul class="times">
        <li class="time-option" data-item="0">7.00PM</li>
        <li class="time-option" data-item="1">7.15PM</li>
        <li class="time-option" data-item="2">7.30PM</li>
        <li class="time-option" data-item="3">7.45PM</li>
        <li class="time-option" data-item="4">8.00PM</li>
   </ul>
   <div class="btn-wrapper form text-center mt-15">
       <button data-accept="true" data-time-exact="false" class="btn booking btn-custom-primary text-small bold text-uppercase">Confirm</button>
   </div>

1
  • you're looping over the items for the bindings, but there is no scenario in which i !== domIndex when clicking it. Commented Apr 12, 2018 at 10:21

4 Answers 4

2

You can firstly remove .active class from all options, then add class to specific one that was clicked:

const timeRangeWrapper = document.querySelector('.time-range');
const timeOptions = timeRangeWrapper.querySelectorAll('.times .time-option');
    timeOptions.forEach((item, i) => {
        const domIndex = item.getAttribute('data-item');
        item.addEventListener('click', () => {
            timeOptions.forEach(option => {
              option.classList.remove('selected');
            })
            if (i == domIndex) {
                item.classList.add('selected');
            }
        });
    });
.selected {
  border: 1px solid red;
}
<div class="time-range">
    <span class="helper">Please select an exact booking time</span>
    <ul class="times">
        <li class="time-option" data-item="0">7.00PM</li>
        <li class="time-option" data-item="1">7.15PM</li>
        <li class="time-option" data-item="2">7.30PM</li>
        <li class="time-option" data-item="3">7.45PM</li>
        <li class="time-option" data-item="4">8.00PM</li>
    </ul>
    <div class="btn-wrapper form text-center mt-15">
        <button data-accept="true" data-time-exact="false" class="btn booking btn-custom-primary text-small bold text-uppercase">Confirm</button>
    </div>
</div>

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

Comments

1

DOM manipulation is much easier with jQuery:

const $items = $(".times .time-option");

$items.on("click", function() {
  $items.removeClass("selected");
  $(this).addClass("selected");
});

Demo

Comments

0

You could have a separate function that removes the class from the selected items first, then adds the selected class to your item.

const timeRangeWrapper = document.querySelector('.time-range');
const timeOptions = timeRangeWrapper.querySelectorAll('.times .time-option');
    timeOptions.forEach((item, i) => {
        item.addEventListener('click', function() {
            removeSelected(timeOptions);
            this.classList.add('selected');
        });
    });

function removeSelected(items) {
  for (var i = 0; i < items.length; i++) {
    items[i].classList.remove('selected');
  }
}

Comments

0
const timeRangeWrapper = document.querySelector('.time-range');
const timeOptions = timeRangeWrapper.querySelectorAll('.times .time-option');
let currentSelected = null; // Store the current selected LI
timeOptions.forEach((item, i) => {
    item.addEventListener('click', () => {
                if (item !== currentSelected) {
                    if (currentSelected) {
                        currentSelected.classList.remove('selected');
                    }
                    item.classList.add('selected');
                    currentSelected = item;
                }
                // else we do nothing, it means it is already selected.
    });
});

Don't use the "DomIndex" variable. Prefer this way, it is more readable and reliable. On click, we test if the one clicked is not the one already clicked. Then if there is an LI already selected, we remove its ".selected" and give it to the new one.

All the other solutions loops on each "LI" to remove a potential ".selected"... it is useless and could be much longer.

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.