2 votes

Bouton nécessitant 2 clics pour fonctionner. - JavaScript standard

Mon code se trouve dans cet extrait de jsfiddle ci-dessous. Chaque fois que je clique sur le bouton de suppression, il faut 2 clics pour supprimer les boîtes qui ont été générées initialement avec du html. Si je les ai ajoutées, alors ces boîtes fonctionnent correctement avec un seul clic. Le problème réside dans ces boîtes qui sont créées à travers le balisage.

Lien vers le code : ici

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            .box-container {
                display: flex;
            }

            .box-item {
                display: inline-block;
                height: 30px;
                width: 30px;
                background: orangered;
                margin: 0 10px;
            }

            .activated {
                background: dodgerblue;
            }

        </style>
    </head>

    <body>
        <div id="box-container">
            <span class="1 box-item"></span>
            <span class="2 box-item"></span>
            <span class="3 box-item"></span>
        </div>

        <button id="add">Add</button>
        <button id="remove">Remove</button>

        <script src="main.js"></script>
    </body>

</html>

CODE JS

const boxContainer = document.getElementById("box-container");
const boxItems = document.getElementsByClassName("box-item");
const addBtn = document.getElementById("add");
const removeBtn = document.getElementById("remove");

function Box(element) {
    this.__el = element;
    this.activated = true;
}

Box.prototype.init = function() {
    this.activateBox();
    this.__el.addEventListener("click", this.toggleActivation.bind(this));
};

Box.prototype.logger = function() {
    console.log(this);
};

Box.prototype.activateBox = function() {
    if (this.activated) {
        this.__el.classList.add("activated");
    }
};

Box.prototype.deactivateBox = function() {
    if (!this.activated) {
        this.__el.classList.remove("activated");
    }
};

Box.prototype.toggleActivation = function() {
    this.__el.classList.toggle("activated");
    return (this.activated = !this.activated);
};

let box = [];

for (let i = 0; i < boxItems.length; i++) {
    box[i] = new Box(boxItems[i]);
    box[i].init();
}

const addBox = function() {
    const node = document.createElement("span");
    node.classList.add("box-item", "activated");
    boxContainer.appendChild(node);
};

function removeBox() {
    boxContainer.removeChild(boxContainer.lastChild);
}

addBtn.addEventListener("click", addBox);
removeBtn.addEventListener("click", removeBox);

PS: J'ai vérifié deux autres questions qui ont le même titre, mais elles ne résolvent pas mon problème.

3voto

CertainPerformance Points 110949

Le problème est que votre HTML inclut des nœuds de texte entre les .box-items:

Donc, lorsque vous appelez

boxContainer.removeChild(boxContainer.lastChild);

Si le dernier nœud enfant d'un parent est un nœud de texte, ce nœud de texte sera sélectionné lorsque vous utiliserez lastChild. Ce n'est pas ce que vous voulez - vous ne voulez pas sélectionner les nœuds de texte. Vous voulez seulement supprimer les éléments , donc vous pourriez supprimer le dernier élément dans le .children à la place :

const { children } = boxContainer;
boxContainer.removeChild(children[children.length - 1]);

Ou, de manière plus élégante, sélectionnez la propriété lastElementChild, grâce au commentaire d'André :

boxContainer.removeChild(boxContainer.lastElementChild);

(assez confusément, l'index final de children n'est pas la même chose que le nœud retourné par lastChild)

const boxContainer = document.getElementById("box-container");
const boxItems = document.getElementsByClassName("box-item");
const addBtn = document.getElementById("add");
const removeBtn = document.getElementById("remove");

function Box(element) {
  this.__el = element;
  this.activated = true;
}

Box.prototype.init = function() {
  this.activateBox();
  this.__el.addEventListener("click", this.toggleActivation.bind(this));
};

Box.prototype.logger = function() {
  console.log(this);
};

Box.prototype.activateBox = function() {
  if (this.activated) {
    this.__el.classList.add("activated");
  }
};

Box.prototype.deactivateBox = function() {
  if (!this.activated) {
    this.__el.classList.remove("activated");
  }
};

Box.prototype.toggleActivation = function() {
  this.__el.classList.toggle("activated");
  return (this.activated = !this.activated);
};

let box = [];

for (let i = 0; i < boxItems.length; i++) {
  box[i] = new Box(boxItems[i]);
  box[i].init();
}

const addBox = function() {
  const node = document.createElement("span");
  node.classList.add("box-item", "activated");
  boxContainer.appendChild(node);
};

function removeBox() {
  boxContainer.removeChild(boxContainer.lastElementChild);
}

addBtn.addEventListener("click", addBox);
removeBtn.addEventListener("click", removeBox);

.box-container {
  display: flex;
}

.box-item {
  display: inline-block;
  height: 30px;
  width: 30px;
  background: orangered;
  margin: 0 10px;
}

.activated {
  background: dodgerblue;
}

Ajouter
Retirer

Ou, vous pouvez simplement changer le HTML de sorte qu'il n'y ait pas de nœuds de texte :

const boxContainer = document.getElementById("box-container");
const boxItems = document.getElementsByClassName("box-item");
const addBtn = document.getElementById("add");
const removeBtn = document.getElementById("remove");

function Box(element) {
  this.__el = element;
  this.activated = true;
}

Box.prototype.init = function() {
  this.activateBox();
  this.__el.addEventListener("click", this.toggleActivation.bind(this));
};

Box.prototype.logger = function() {
  console.log(this);
};

Box.prototype.activateBox = function() {
  if (this.activated) {
    this.__el.classList.add("activated");
  }
};

Box.prototype.deactivateBox = function() {
  if (!this.activated) {
    this.__el.classList.remove("activated");
  }
};

Box.prototype.toggleActivation = function() {
  this.__el.classList.toggle("activated");
  return (this.activated = !this.activated);
};

let box = [];

for (let i = 0; i < boxItems.length; i++) {
  box[i] = new Box(boxItems[i]);
  box[i].init();
}

const addBox = function() {
  const node = document.createElement("span");
  node.classList.add("box-item", "activated");
  boxContainer.appendChild(node);
};

function removeBox() {
  boxContainer.removeChild(boxContainer.lastChild);
}

addBtn.addEventListener("click", addBox);
removeBtn.addEventListener("click", removeBox);

.box-container {
  display: flex;
}

.box-item {
  display: inline-block;
  height: 30px;
  width: 30px;
  background: orangered;
  margin: 0 10px;
}

.activated {
  background: dodgerblue;
}

Ajouter
Retirer

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X