Переменная сама сбрасывается JS
Я еще не очень опытный, поэтому решил обратиться сюда
У меня есть фрагмент кода:
let labels = document.getElementsByTagName('label');
let label,
input;
// Для каждого label создаем eventListener
for (let index = 0; index < labels.length; index++) {
labels[index].addEventListener('click', () => {
// 1. Получаем сам label
label = labels[index];
console.log(label);
// 2. Получаем привязанный к нему input
input = document.getElementById(label.getAttribute('for'));
// 3. Меняем состояние input
input.checked = !(input.checked);
// 4. Меняем фон
label.style.backgroundColor = input.checked ? '#E95D00' : '#C4C4C4';
})
}
Этот код отвечает за вот этот фрагмент HTML:
<div class="radio__container">
<div class="radio__item">
<input class="radio__button"type="radio" id="vk">
<label for="vk">Вконтакте</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="youtube">
<label for="youtube">Youtube</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="rutube">
<label for="rutube">Rutube</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="telega">
<label for="telega">Telegram</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="ok">
<label for="ok">Одноклассники</label>
</div>
</div>
- Я кликаю на один label, предположим на "Вконтакте"
- Как и положено
input.checked, относящийся<input class="radio__button"type="radio" id="ok">, принимает значение true из дефолтного для чекбокса false - Я кликаю на этот блок снова и как и положено чекбокс принял значение false
- С этого момента начинается проблема. Сразу после выполнения предыдущего eventListener'а значение
input.checkboxсбрасывается на true.
Я достаточно долго время потратил на это, пытаясь прийти к решению этой проблемы, изучая её в отладчике...Буду рад любой помощи!
Ответы (2 шт):
Если очень коротко, то проблема Вашего кода заключается в том что Вы упустили из виду один важный момент — создание label с указанным for привязывает ее к конкретному элементу, что в свою очередь позволяет по клику на нее переключать значение опции. Т.е. у вас накладываются оба переключения, автоматическое и логическое. Стоит убрать аттрибут for все заработает:
let labels = document.getElementsByTagName('label');
let label, input;
// Для каждого label создаем eventListener
for (let index = 0; index < labels.length; index++) {
labels[index].addEventListener('click', () => {
// 1. Получаем сам label
label = labels[index];
// 2. Получаем привязанный к нему input
input = label.previousElementSibling
// 3. Меняем состояние input
input.checked = !input.checked
// 4. Меняем фон
label.style.backgroundColor = input.checked ? '#E95D00' : '#C4C4C4';
})
}
<div class="radio__container">
<div class="radio__item">
<input class="radio__button"type="radio" id="vk">
<label >Вконтакте</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="youtube">
<label >Youtube</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="rutube">
<label >Rutube</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="telega">
<label >Telegram</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="ok">
<label >Одноклассники</label>
</div>
</div>
Замечу, что previousElementSibling находит предедущий элемент в разметке.
Но тут встает другой вопрос, писать код хочется по семантике. И тогда мы возвращаем аттрибут, но меняем подход работы с нашими элементами, т.е. работаем не конкретно с ними, а с данными, и этот подход я всегда советую использовать так как DOM крайне не надежен - например в приведенном коде можно кликнуть непосредственно на саму опцию (не на подпись) что создаст путаницу.
let state = {}
document.querySelector('.radio__container').onclick = function(event){
event.preventDefault()
if (event.target.tagName === 'LABEL'){
const label = event.target
const id = label.getAttribute('for')
state[id] = !state[id]
label.previousElementSibling.checked = state[id]
label.style.backgroundColor = state[id] ? '#E95D00' : '#C4C4C4'
}
}
<div class="radio__container">
<div class="radio__item">
<input class="radio__button"type="radio" id="vk">
<label for="vk">Вконтакте</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="youtube">
<label for="youtube">Youtube</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="rutube">
<label for="rutube">Rutube</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="telega">
<label for="telega">Telegram</label>
</div>
<div class="radio__item">
<input class="radio__button"type="radio" id="ok">
<label for="ok">Одноклассники</label>
</div>
</div>
По клику у radio, действием по умолчанию можно только выставить checked. Т.к. вы не отключаете это действие, то срабатывает сначало ваш код, а потом действие по умолчанию. Как вариант, можете отключить это действие...
let labels = document.getElementsByTagName('label');
let label,
input;
// Для каждого label создаем eventListener
for (let index = 0; index < labels.length; index++) {
labels[index].addEventListener('click', (e) => {
// 0. Сбрасываем действие по умолчанию
e.preventDefault();
// 1. Получаем сам label
label = labels[index];
console.log(label);
// 2. Получаем привязанный к нему input
input = document.getElementById(label.getAttribute('for'));
// 3. Меняем состояние input
input.checked = !(input.checked);
// 4. Меняем фон
label.style.backgroundColor = input.checked ? '#E95D00' : '#C4C4C4';
})
}
Или, как вариант, вместо radio использовать checkbox