In short, the problem is that you are trying to work with the state not through a property , but through an attribute .
Let's go through the steps and see what happens. So that the color does not confuse you, turn off its change and monitor only the state of checkboxes.
Before you start, you should talk about two important points that for some reason are not covered in the Russian-speaking segment of the Internet.
State flag
According to the specification, the input has a boolean flag of the changed state ( dirty checkedness flag ), something like a seal, by which it is possible to check whether the user has changed the state of the checkbox. When the page loads, it is false.
HTML attribute ≠ DOM property
Elements have properties and attributes, they are different entities. Often, their values are related to each other, but, there are many but. For example, the id attribute is associated with the id property, so you can write elem.id = 'newId' and see the changes in the DOM. However, editing the text in <input type="text"> , you will not notice changes in the value attribute, since it is synchronized with the defaultValue property.
And finally, the main thing.
The state of the element is reflected through the property . In the case of the checkbox, the current state ( on / off ) can be obtained and recorded by referring to the elem.checked property. Let's take a look at how your code works “on attributes” and how it can be rewritten “on properties”.
So, we successively call out 4 Sberbank checkboxes.
In your case, first click on the first checkbox, changing the state and the dirty checkedness flag (it becomes true). And only then does your function. The preliminary result before executing the function:
☑️🏳 ☑️🏳 ☑️🏳
1.1. In the function, you check whether the element has the checked attribute, mistakenly assuming that the change in the input state should also affect the attribute, but such a dependency is simply not provided. You can verify this by creating the usual <input type="checkbox" checked> , clicking on it and checking in the inspector what became of the attribute (spoiler: nothing). The result: the check for the presence of the attribute is successful, because it was originally in the code.
1.2. Further, by code, you remove the checked attribute from inputs with the same value. Again, we ’ll refer to the specification : when removing the checked attribute, the browser should change the state to false , but only if the changed state flag is false . Total:
⬜️🏳 ⬜️🏳 ⬜️🏳
Now you click on the second checkbox. Its state changes to the marked one, the changed state flag becomes true . Preliminary result:
☑️🚩 ⬜️🏳 ⬜️🏳
2.1. Since all checkboxes of Sberbank have the checked attribute in clause 1.2, in the function you submit the else condition.
2.2. Here checkboxes are set to the checked attribute. When an attribute is added, the changed state flag must also be checked , so the browser will change the state to on only those 2 checkboxes whose flag is still false . Total:
☑️🚩 ☑️🏳 ☑️🏳
Click on the third checkbox. Its status becomes off , and the dirty checkedness flag is true . Preliminary result:
☑️🚩 ⬜️🚩 ☑️🏳
3.1. We successfully pass the condition in the function, because we added attributes in section 2.2.
3.2. We remove checkbox attribute checked . The browser changes the state to off only on the 4th checkbox, since the rest of the flags are true. Total:
⬜️🚩☑️🚩⬜️🚩⬜️🏳
Click on the fourth checkbox: it was off , it became on . The altered state flag also becomes true . Preliminary result:
⬜️🚩☑️🚩⬜️🚩☑️🚩
4.1. We fall into the else condition, since the attributes are removed in Section 3.2.
4.2. Add checkbox checked attribute. The browser looks at the input, all have true flags - it spreads its hands, it does not switch anything. Total:
⬜️🚩☑️🚩⬜️🚩☑️🚩
We work with the state through the properties
Instead of elem.hasAttribute we will get the current state of the checkbox by accessing the elem.checked property. To change the state, we will overwrite the same property.
Also, for brevity, I made a few less important changes:
- instead of passing
this element, it is retrieved from event.target - instead of a loop
for search, elements are implemented through the array method map (but querySelectorAll does not return an array, but an object of type NodeList , we will lend the method to the array prototype); - instead of
if used ternary operator .
function have_check() { var elem = event.target; var elems_group = document.querySelectorAll('input[value="' + elem.value + '"]'); Array.prototype.map.call(elems_group, function(checkbox) { checkbox.checked = elem.checked; checkbox.parentNode.style.backgroundColor = elem.checked ? 'white' : 'red'; }); }
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <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()" 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()" 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()" 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()" 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()" 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()" 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()" 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()" checked> </td> </tr> </table> </body> </html>