`appendChild` inside a `for` loop just replaces item created by `createElement` - javascript

I Googled a lot about creating multiple items with appendChild, but I’m not understanding how it works. My appendChild just replaces instead of adding many.
var startGame;
var cards = 16;
var newDeck = [];
startGame = function(){
var startBtn = document.getElementById('start');
var board = document.getElementById('game-board');
var backside = document.createElement("div");
backside.className = 'card';
startBtn.onclick = function(){
removeButton = document.getElementById("start");
removeButton.parentNode.removeChild(removeButton);
for(var i = 0; i < cards; i++){
board.appendChild(backside);
}
};
};
I also read you can do this with innerHTML, but that leaves me confused as well. Does anyone have a more detailed explanation on how to make this work?

From the MDN on appendChild :
Adds a node to the end of the list of children of a specified parent
node. If the node already exists it is removed from current parent
node, then added to new parent node.
When you append an element that is yet in the DOM, you move it from its old place. Create the element in the loop :
startBtn.onclick = function(){
removeButton = document.getElementById("start");
removeButton.parentNode.removeChild(removeButton);
for(var i = 0; i < cards; i++){
var backside = document.createElement("div");
backside.className = 'card';
board.appendChild(backside);
}
};

I'm creating a single element and trying to re-add it multiple times, andI need to create multiple elements.
When I run document.createElement() to create an element, .appendChild() is just setting the location. So I created one element and then moved it to the same place many times. I want to instead create many elements and set their location once each.
var backside;
startBtn.onclick = function () {
removeButton = document.getElementById("start");
removeButton.parentNode.removeChild(removeButton);
for (var i = 0; i < cards; i++) {
backside = document.createElement("div");
backside.className = "card";
board.appendChild(backside);
}
};
or alternatively (shorter but less flexible, only use this for a one-off)
startBtn.onclick = function () {
removeButton = document.getElementById("start");
removeButton.parentNode.removeChild(removeButton);
for (var i = 0; i < cards; i++) {
board.appendChild("<div class='card'></div>");
}
};

Related

Lottery Javascript cant clear the array

So I'm making a simulation of the lottery. I generate 6 numbers between 0 and 40 and show them in the html id 'generated'. My problem is that if I click a second time on 'generate' (in my html page), the previous generated numbers are still a part of the array and still show up. Does anybody know how to clear the array when pushed on the button multiple times?
This is my Javascript code:
'use strict';
function generatenumbers(){
let number = [];
let i;
i=0;
for(i= 0; i <= 5; i++){
number[i] = Math.floor(Math.random()*40);
}
i = 0;
for(i=0; i<= number.length - 1; i++){
let node = document.createElement("LI");
let textnode = document.createTextNode(number[i]);
node.appendChild(textnode);
document.getElementById("generated").appendChild(node);
}
}
You are supposed to remove the previously appended children then add new ones.
var list = document.getElementById("generated");
list.removeChild(list.childNodes[0]); // for removing first child only
//for removing all children
var list = document.getElementById("genrated");
while (list.firstChild) {
list.removeChild(list.firstChild);
}
you don't want to clear the array...you want to clear the document.getElementById("generated") element before you call the loop, that way, there will always be 6 LI elements at the end of the function.
document.getElementById("generated").innerHTML = ""; // clear the element
for(i=0; i<= number.length - 1; i++){
let node = document.createElement("LI");
let textnode = document.createTextNode(number[i]);
node.appendChild(textnode);
document.getElementById("generated").appendChild(node);
}

innerHTML modifying whole array

I have got an unexpected behavior from my Javascript code. I'm creating a line of table with document.createElement("tr") and an array of cells with that code:
cellule = new Array(3).fill(document.createElement("td"));
But when I'm filling it with my values using innerHTML property case by case, the whole array is modified. Here is full code:
ligne = document.createElement("tr");;
cellule = new Array(3).fill(document.createElement("td"));
cellule[0].innerHTML = "Chat";
cellule[1].innerHTML = "Chien";
cellule[2].innerHTML = "Alligator";
ligne.appendChild(cellule[0]);
ligne.appendChild(cellule[1]);
ligne.appendChild(cellule[2]);
maTable.appendChild(ligne);
Results are :
cellule[0] => "Alligator"
cellule[1] => "Alligator"
cellule[2] => "Alligator"
Why is my whole array filled with the last innerHTML used?
Because 'filll' was used, the same td was copied, causing an issue. One way is to create an independent td.
ligne = document.createElement("tr");
var datas = ['Chat', 'Chien', 'Alligator'];
for(var i=0; i<datas.length; i++) {
var td = document.createElement("td");
td.innerHTML = datas[i];
ligne.appendChild(td);
}
maTable.appendChild(ligne);
Your issue is with:
cellule = new Array(3).fill(document.createElement("td"));
Here you are creating an array with 3 of the same td elements. So when you change the one at index 0, you are also changing the one at index 1 and 2 as you are referencing the same element in memory.
An easy way to fix this is to manually create an array using a for loop and pushing unique references of the element into your cellule array.
See example below:
var maTable = document.getElementById("myTable");
var ligne = document.createElement("tr");;
var cellule = [];
for(var i = 0; i < 3; i++) {
cellule.push(document.createElement("td"));
}
cellule[0].textContent = "Chat"; // use textContent instead of innerHTML if only adding text
cellule[1].textContent = "Chien";
cellule[2].textContent = "Alligator";
ligne.appendChild(cellule[0]);
ligne.appendChild(cellule[1]);
ligne.appendChild(cellule[2]);
maTable.appendChild(ligne);
<table id="myTable" border="1"></table>
fill add the same element (with the same reference) into your array.
You can put your elements with another way, like
cellule = [];
for (let i = 3; i--;) {
cellule.push(document.createElement("td"));
}
or
cellule = new Array(3);
for (let i = cellule.length; i--;) {
cellule[i] = document.createElement("td");
}
When fill gets passed an object, it will copy the reference and fill
the array with references to that object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill#Description
Here is one of the way you could achieve the same.
cellule = new Array(3).fill("")
cellule.forEach((el,index) => cellule[index] = document.createElement("td"))
cellule[0].textContent = "Chat";
cellule[1].textContent = "Chien";
cellule[2].textContent = "Alligator";
console.log(cellule[0].textContent);
console.log(cellule[1].textContent);
console.log(cellule[2].textContent);

remove all images of a cloned div

I want to remove images from a cloned div.
I tried this:
var divToPrint = document.getElementById(id);
var clonedDiv = jQuery.extend(true, {}, divToPrint)
var images = [].slice.call(clonedDiv.getElementsByTagName('img'), 0);
var l = images.length;
for (var i = 0; i < l; i++) {
images[i].parentNode.removeChild(images[i]);
}
This line is wrong, I don't know how to get all images of the cloned div:
var images = [].slice.call(clonedDiv.getElementsByTagName('img'), 0);
I get this error:
'getElementsByTagName' called on an object that does not implement interface Element.
This is not how you clone an element:
var clonedDiv = jQuery.extend(true, {}, divToPrint)
This is how you clone an element with the DOM (cloneNode):
var clonedDiv = divToPrint.cloneNode(true);
Then to find the img elements within the clone (with the DOM):
var images = clonedDiv.getElementsByTagName("img");
To remove them (with the DOM's removeChild):
while (images.length) {
images[0].parentNode.removeChild(images[0]);
}
The NodeList returned by getElementsByTagName is live, so the image will disappear from the list, putting a new one at index 0, so that removes images one by one until they're all removed. If you might have a polyfilled getElementsByTagName (but that's unlikely) that doesn't do that, just loop in reverse order instead:
for (var i = images.length - 1; i >= 0; --i) {
images[i].parentNode.removeChild(images[i]);
}
Or all of that with jQuery (clone, remove):
var clonedDiv = jQuery(divToPrint).clone();
clonedDiv.find("img").remove();

JQuery not replacing html

here is the deal, i have the following jquery code that should add the array values to specific #id, buf it does not replace the code, only add more, and i need a little help to make it replace the html on othe link click.
Code:
function changeClass(curClass){
switch(curClass){
case "Schoolgirl":
case "Fighter":
var charSkillsNames = ["text1","text2","text4","text5"];
//loop show array values
listSkillsNames(charSkillsNames);
break;
}
}
function listSkillsNames(arr){
var length = arr.length,
element = null;
$("#skills").html(function(){
for (var i = 0; i < length; i++) {
element = arr[i];
$(this).append("<li>"+element+"</li>");
}
});
}
this works well but i need it to replace the html inside the "#skills" id when i click on the link that makes it work
PS: problem is really here
The issue is that you don't empty the HTML of #skills element. Use $("#skills").html("") to empty it.
function listSkillsNames(arr){
var length = arr.length,
element = null;
var $skills = $("#skills");
$skills.html(""); // empty the HTML
for (var i = 0; i < length; i++) {
element = arr[i];
$skills.append("<li>"+element+"</li>"); // append new items
}
}
The problem is because you are keep appending new items to the element always without removing the existing items.
Just empty the skill element, also there is no need to use the .html(function(){}) here
function listSkillsNames(arr) {
var length = arr.length,
element = null;
var $skill = $("#skills").empty();
for (var i = 0; i < length; i++) {
element = arr[i];
$skill.append("<li>" + element + "</li>");
}
}

appendChild to array only appends to last element

As you can see I am still a novice in javascript
Why is it so that you can append a Textnode only once? When you add it again somewhere else the first one disappears
I do not need a solution to a problem I was just curious what is causing this behavior.
Example where the textnode is only added to the last element of an array:
function hideAdd(){
var hide = document.createTextNode('Afbeelding verbergen');
var afb = collectionToArray(document.getElementsByTagName('img'));
afb.pop();
var divs = [];
for (i=0; i < afb.length; i++){
divs.push(afb[i].parentNode);
}
console.log(divs);
for ( i = 0; i < divs.length;i++){
divs[i].appendChild(hide);
}
}
This is where you use an unique textnode so it works:
function hideAdd(){
var hide = []
var afb = collectionToArray(document.getElementsByTagName('img'));
afb.pop();
var divs = [];
for (i=0; i < afb.length; i++){
divs.push(afb[i].parentNode);
hide[i] = document.createTextNode('Afbeelding verbergen');
}
console.log(divs);
for ( i = 0; i < divs.length;i++){
divs[i].appendChild(hide[i]);
}
}
Short answer is the DOM is a tree, not a network. Each node can have only one parent. If you could add a node in more than one location, it would have more than one parent.

Categories