J'ai plusieurs éléments html, qui contiennent un nombre.
Chaque clic sur le bouton réduit ce nombre de -1.
Lorsque le nombre est égal à 0, l'élément doit être supprimé.

Mon code ne supprime que la moitié des éléments, et je ne comprends pas pourquoi...
DÉMO JsFiddle

<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>50</div>

<button id='bubu'>Remove</button>

JS:

$(document).on('click','#bubu',function(){
  var x = document.getElementsByClassName('moo');
  for(var i = 0; i < x.length; i++){
    if( Number(x[i].innerHTML) > 0 ) {
      x[i].innerHTML = Number(x[i].innerHTML) - 1;
    }
    if( Number(x[i].innerHTML) == 0 ){
      x[i].remove();
    } 
  }
});

(i) La suppression avec replace et innerHTML est impossible, il s'agit d'un html simplifié.

0
Bubu 16 mars 2019 à 16:47

2 réponses

Meilleure réponse

C'est parce que lorsque vous supprimez des éléments, la longueur de la liste de nœuds x diminue et vous utilisez cette longueur comme condition pour boucler jusqu'à.

Si vous supprimez des éléments à la fin de la liste des nœuds et que vous travaillez en arrière, cette approche fonctionnera car la suppression de la fin permet à la condition de boucle de se réduire sans sauter aucun élément de la liste des nœuds :

$(document).on('click','#bubu',function(){
  var x = document.getElementsByClassName('moo');
  for(var i = x.length-1; i >= 0 ; i--){
    if( Number(x[i].innerHTML) > 0 ) {
      x[i].innerHTML = Number(x[i].innerHTML) - 1;
    }
    if( Number(x[i].innerHTML) == 0 ){
      x[i].remove();
    } 
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>50</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<button id='bubu'>Remove</button>

Cela dit, il y a un certain nombre de problèmes avec votre approche :

.getElementsByClassName() renvoie une liste de nœuds "en direct" et ne devrait vraiment pas être utilisé. Lisez un autre post du mien qui explique cela plus en détail.

.innerHTML a des implications en matière de sécurité et de performances et ne doit être utilisé que lorsque la chaîne avec laquelle vous travaillez contient du HTML. Utilisez .textContent lorsqu'il n'y a pas de code HTML dans la chaîne.

Au lieu de vous fier à des compteurs numériques que vous devez gérer avec des boucles, utilisez Arrays et sa méthode intégrée .forEach() pour l'itération.

Voici le même résultat, réalisé de manière plus concise et performante :

$('#bubu').on('click', function(){
  // Get the elements into an Arrray without a live node list
  var elements = Array.prototype.slice.call(document.querySelectorAll(".moo"));
  
  // Loop over the array
  elements.forEach(function(element){
    // Get the text of the element and convert to a number. The prepended + symbol does this.
    let elNum = +element.textContent;
    
    // Instead of two consecutive if/then statements, use one with an else if
    if(elNum > 0) {
      element.textContent = --elNum;  // Just set the content to 1 less
    } else if(elNum === 0){
      element.remove();
    }
  });
});
.moo { display:inline-block; font-size:1.5em; color:#f00; border:1px solid grey; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>4</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>50</div>
<div class='moo'>3</div>
<div class='moo'>5</div>
<button id='bubu'>Remove</button>
2
Scott Marcus 16 mars 2019 à 14:02

GetElementsByClassName renvoie une collection dynamique, de sorte que lorsque vous supprimez des éléments du DOM, la taille de la collection diminue, le moyen le plus simple de résoudre ce problème consiste à convertir la collection dans un tableau standard

var x = [].slice.call(document.getElementsByClassName('moo'))
1
user3094755 16 mars 2019 à 13:59