There are several elements on the page that are clickable (I use the data-checked custom attribute). Repeated click removes this state. Everything works well, but you need to make a function that would clear all selected items and return them to their original state. Attach a button, she attached a function, but it does not work. Those. when I click for example 3-4 labels, and I call this function, then the selection is not removed from all. Try to select (press and gray) 4 marks, and then call the cleaning function. selection is removed only from two. This is some kind of nonsense.

http://jsfiddle.net/FzZ2H/24/

This is the function that does the traversal, even iteration is written to the console fewer than expected.

 var uncheck_all_cells = function () { var labels = document.getElementsByClassName("selected_cell"); Array.prototype.forEach.call(labels, function (label) { uncheck_cell(label); console.log("iteration"); }); console.log(labels); }; 
  • Thank you all very much, everyone has simple and clear answers - arg

3 answers 3

This is a rather interesting, but well-known trap.

The problem is that labels change when you change the class of its elements (in your case, call uncheck_cell ). What happens next is obvious - forEach already iterates incorrectly, since the elements are shifted.

How to get around?

The simplest solution is to go through the list in the reverse order.

 for (var i = labels.length - 1; i >= 0; --i) { uncheck_cell(labels[i]); console.log("iteration"); }; 

Working version: http://jsfiddle.net/FzZ2H/25/

Also keep in mind that getElementsByClassName is not available in all browsers, in particular, it is not in IE9.

You can implement your own getElementsByClassName as follows:

 function getElementsByClassName(node, classname) { var a = []; var re = new RegExp('(^| )'+classname+'( |$)'); var els = node.getElementsByTagName("*"); for(var i=0,j=els.length; i<j; i++) if(re.test(els[i].className))a.push(els[i]); return a; } 

Read more about this: https://stackoverflow.com/questions/7410949/

    Well, it’s generally better to turn the HTML collection into a real array:

     var labels = document.getElementsByClassName("selected_cell"); labels = Array.prototype.slice.call(labels); 

    Now labels is an array, with all available methods, and then do so

     labels.forEach(function (label) { uncheck_cell(label); }); 

    This method works: demo

      If you're still using jQuery, why not use it to the fullest?

       var uncheck_cell = function (label) { $(label).removeClass("selected_cell").attr('data-checked', 'false'); }; var check_cell = function (label) { $(label).addClass("selected_cell").attr('data-checked', 'true'); }; var uncheck_all_cells = function () { var labels = $(".selected_cell"); labels.each(function() { uncheck_cell($(this)); }); }; 

      Everything is much shorter and works great