Как правильно работать со списком checkbox'ов?

201
13 июня 2018, 11:10

Это фрагмент таблицы с суммами для загрузки в БД. При загрузке (в параметрах хранимой процедуры БД) у каждого банка есть свой параметр, который передается в атрибуте чекбокса: value. Мне нужно, чтобы при клике на одном из чекбоксов галка устанавливалась или снималась на всех чекбоксах с таким значением value (и при снятии галки со всех чекбоксов с одинаковым value цвет ячейки подсвечивается красным, а если снова поставить галку - то фон ячейки становится белым). Я реализовала это через атрибуты в обработчике клика на чекбоксе:

function have_check(elem) { 
  var param_value = elem.value; 
  var elems_group = document.querySelectorAll('input[value=\'' + param_value + 
    '\']'); 
 
  if (elem.hasAttribute('checked')) { 
    for (var i = elems_group.length - 1; i >= 0; i--) { 
      elems_group[i].removeAttribute('checked'); 
      elems_group[i].parentNode.style.backgroundColor = 'red'; 
    } 
  } else { 
    for (var i = elems_group.length - 1; i >= 0; i--) { 
      elems_group[i].parentNode.style.backgroundColor = 'white'; 
      elems_group[i].setAttribute('checked', true); 
    } 
  } 
}
<table> 
  <tr> 
    <th>Дата</th> 
    <th>Сборщик</th> 
    <th>Сумма</th> 
    <th>Загрузить</th> 
  </tr> 
  <tr> 
    <td>13.05.2018</td> 
    <td>Сбербанк</td> 
    <td>337.35</td> 
    <td><input type="checkbox" value="1_2" onclick="have_check(this)" checked></td> 
  </tr> 
  <tr> 
    <td>18.05.2018</td> 
    <td>Сбербанк</td> 
    <td>248.9</td> 
    <td><input type="checkbox" value="1_2" onclick="have_check(this)" checked></td> 
  </tr> 
  <tr> 
    <td>21.05.2018</td> 
    <td>Сбербанк</td> 
    <td>717.6</td> 
    <td><input type="checkbox" value="1_2" onclick="have_check(this)" checked></td> 
  </tr> 
  <tr> 
    <td>22.05.2018</td> 
    <td>Сбербанк</td> 
    <td>723.45</td> 
    <td><input type="checkbox" value="1_2" onclick="have_check(this)" checked></td> 
  </tr> 
  <tr> 
    <td>22.05.2018</td> 
    <td>Альфабанк</td> 
    <td>723.45</td> 
    <td><input type="checkbox" value="2_2" onclick="have_check(this)" checked></td> 
  </tr> 
  <tr> 
    <td>24.05.2018</td> 
    <td>Альфабанк</td> 
    <td>655.13</td> 
    <td><input type="checkbox" value="2_2" onclick="have_check(this)" checked></td> 
  </tr> 
  <tr> 
    <td>21.05.2018</td> 
    <td>ВТБ-24</td> 
    <td>356.19</td> 
    <td><input type="checkbox" value="3_2" onclick="have_check(this)" checked></td> 
  </tr> 
  <tr> 
    <td>23.05.2018</td> 
    <td>ВТБ-24</td> 
    <td>554.20</td> 
    <td><input type="checkbox" value="3_2" onclick="have_check(this)" checked></td> 
  </tr> 
</table>

Все бы ничего, но если последовательно кликать на 1-ый, потом 2-ой, потом 3-й и потом 4-й чекбокс, то видно, что флажки в группе с value= '1_2' начинают хаотично выделяться и сниматься. В общем, работает не так как надо, хотя цвет ячейки меняется правильно.

Подскажите, пожалуйста, может эту одновременную установку/снятие флажков для группы надо не через атрибут, а через свойство делать? Или в коде у меня какие-то ошибки, из-за которых программа ведет себя не так, как хотелось бы?

Answer 1

Если вкратце, то проблема в том, что вы пытаетесь работать с состоянием не через свойство, а через атрибут.

Давайте пройдёмся по шагам и поймём, что происходит. Чтобы цвет не сбивал вас с толку, отключите его изменение и следите только за состоянием чекбоксов.

Перед началом следует рассказать о двух важных моментах, которые в русскоязычном сегменте интернета почему-то не освещены.

Флаг изменённого состояния

Согласно спецификации инпут имеет булевый флаг изменённого состояния (dirty checkedness flag), что-то вроде пломбы, по которой можно проверить, менял ли пользователь состояние чекбокса. При загрузке страницы он равен false.

HTML-атрибут ≠ DOM-свойство

У элементов есть свойства и атрибуты, это разные сущности. Зачастую их значения связываются между собой, но, есть много но. Например, атрибут id связывается со свойством id, поэтому вы можете написать elem.id = 'newId' и увидеть изменения в DOM. Однако, редактируя текст в <input type="text">, вы не заметите изменений атрибута value, поскольку тот синхронизируется со свойством defaultValue.

И наконец, главное.

Состояние элемента отражается через свойство. В случае с чекбоксом текущее состояние (вкл/выкл) можно получить и записать, обратившись к свойству elem.checked. Давайте посмотрим, как работает ваш код «на атрибутах» и как его можно переписать «на свойствах».

Итак, последовательно прокликаем 4 чекбокса Сбербанка.

  1. В вашем случае сначала происходит клик по первому чекбоксу, меняющий состояние и dirty checkedness flag (он становится true). И только затем выполняется ваша функция. Предварительный итог до выполнения функции:

    ⬜️

    Answer 2

    Попробуй не ставить аттрибут, а немного другой метод

    elem.checked = true | false

            function have_check(elem) { 
                var param_value = elem.value; 
                var elems_group = document.querySelectorAll('input[value=\'' + param_value + 
                    '\']'); 
     
                if (elem.checked) { 
                    for (var i = elems_group.length - 1; i >= 0; i--) { 
                        elems_group[i].checked = true; 
                        elems_group[i].parentNode.style.backgroundColor = 'white'; 
                    } 
                } else { 
                    for (var i = elems_group.length - 1; i >= 0; i--) { 
                        elems_group[i].parentNode.style.backgroundColor = 'red'; 
                        elems_group[i].checked = false; 
                    } 
                } 
            }
        <table> 
            <tbody> 
                <tr> 
                    <th>Дата</th> 
                    <th>Сборщик</th> 
                    <th>Сумма</th> 
                    <th>Загрузить</th> 
                </tr> 
                <tr> 
                    <td>13.05.2018</td> 
                    <td>Сбербанк</td> 
                    <td>337.35</td> 
                    <td><input type="checkbox" name='1_2' value="1_2" onclick="have_check(this)" checked></td> 
                </tr> 
                <tr> 
                    <td>18.05.2018</td> 
                    <td>Сбербанк</td> 
                    <td>248.9</td> 
                    <td><input type="checkbox" name='1_2' value="1_2" onclick="have_check(this)" checked></td> 
                </tr> 
                <tr> 
                    <td>21.05.2018</td> 
                    <td>Сбербанк</td> 
                    <td>717.6</td> 
                    <td><input type="checkbox" name='1_2' value="1_2" onclick="have_check(this)" checked></td> 
                </tr> 
                <tr> 
                    <td>22.05.2018</td> 
                    <td>Сбербанк</td> 
                    <td>723.45</td> 
                    <td><input type="checkbox" name='1_2' value="1_2" onclick="have_check(this)" checked></td> 
                </tr> 
                <tr> 
                    <td>22.05.2018</td> 
                    <td>Альфабанк</td> 
                    <td>723.45</td> 
                    <td><input type="checkbox" value="2_2" onclick="have_check(this)" checked></td> 
                </tr> 
                <tr> 
                    <td>24.05.2018</td> 
                    <td>Альфабанк</td> 
                    <td>655.13</td> 
                    <td><input type="checkbox" value="2_2" onclick="have_check(this)" checked></td> 
                </tr> 
                <tr> 
                    <td>21.05.2018</td> 
                    <td>ВТБ-24</td> 
                    <td>356.19</td> 
                    <td><input type="checkbox" value="3_2" onclick="have_check(this)" checked></td> 
                </tr> 
                <tr> 
                    <td>23.05.2018</td> 
                    <td>ВТБ-24</td> 
                    <td>554.20</td> 
                    <td><input type="checkbox" value="3_2" onclick="have_check(this)" checked></td> 
                </tr> 
            </tbody> 
        </table>

READ ALSO
Как убрать лишние символы @ из json файла?

Как убрать лишние символы @ из json файла?

Получаю данные из JSON файла более 3к строк и вывожу на страницу через jsrender, но столкнулся с проблемой, в конечных объектах, в начале у свойств,...

297
visual studio Откатить публикацию

visual studio Откатить публикацию

Я опубликовал новую версию проекта, нажав кнопку "Опубликовать"(Web deploy)Но сайт отказался запускаться с ошибкой 502

242
Как реализовать скил &ldquo;Poison&rdquo; ? Unity C#

Как реализовать скил “Poison” ? Unity C#

Есть абстрактный класс Creature от которого наследуются два класса: Rogue, Goblin(в этих классах пара скиллов и статы)Есть класс Fight(в нем реализован...

232