appendChild to array only appends to last element - javascript

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.

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);
}

Filter an array of tags with props

Hei guys, im struggling with a problem here. I selected all elements from body tag into an array like so :
var DOMelementsOrder = [];
var elements = document.querySelectorAll('body > div');
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
DOMelementsOrder.push(element);
console.log(DOMelementsOrder[i].offsetLeft);
}
What i'm trying to reach is to sort the tags in array by theyr prop offset left.
The console in for loop return "40,200,85". What i try to achieve is to sort the tags in DOMelementsOrder in order of theyr offsetLeft.
Any help? Thanks in advance.
ONLY WITH PURE JS
EDIT:
What i have tryed:
function bubbleSort(a, b)
{
var swapped;
do {
swapped = false;
for (var i=0; i < a.length-1; i++) {
if (a[i].b > a[i+1].b) {
var temp = a[i].b;
a[i].b = a[i+1].b;
a[i+1].b = temp;
swapped = true;
}
}
} while (swapped);
}
bubbleSort(DOMelementsOrder, DOMelementsOrder.offsetLeft);
console.log(DOMelementsOrder);
Use the Array.prototype.sort method and pass a compare function to compare the values of offsetLeft for each element.
// qSA doesn't return an array, so we have to convert it first
var elements = Array.prototype.slice.call(document.querySelectorAll('body > div'));
// then we can sort
var orderedElements = elements.sort(function(a, b) {
return a.offsetLeft - b.offsetLeft;
});

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` inside a `for` loop just replaces item created by `createElement`

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>");
}
};

How to count the number of line boxes in a DIV or P

<div><span>aaaaaa</span> ... (many other span here) ... <span>zzzzzz</span></div>
In that case, the boxes span are placed on few line-boxes inside the div.
(The span elements can use different font-size.)
1) How can we know the number of the line-boxes ?
2) Can we know on which line-boxe an element span is placed ?
3) Can we know on which line-boxe the caret is placed (contenteditable) ?
Thank you
I'll suppose the DOM in your example is an effective example of the actual complexity of your DOM, and that a "line-boxe" is just a line of text.
1-2) For every <span> inside the <div>, you can count the number of lines they span with something like this:
var spans = div.getElementsByTagName("span"), spandata = [];
for (var i = 0; i < spans.length; i++) {
var rects = spans[i].getClientRects();
if (i > 0)
if (rects[0].bottom > obj.rects[obj.rects - 1].bottom)
var inirow = obj.lastRow + 1;
else var inirow = obj.lastRow;
var obj = {
element: spans[i],
rects: rects,
iniRow: inirow,
lastRow: inirow + rects.length - 1
};
spandata.push(obj);
}
Now spandata is a list of all the data you want about the <span> elements. I'm also supposing that each one of them may span through more than one line.
Keep in mind that getClientRects has some issues in IE<8.
3) In modern browsers, the getSelection method can help you:
var sel = window.getSelection();
if (sel.type === "Caret")
var span = sel.anchorNode.parentNode;
About the line position, I must say it's not an easy task. You can't easily get the page position of the caret. The simplest thing you can do is to place a dummy inline element in the place of the caret:
var text = sel.anchorNode.nodeValue;
sel.anchorNode.nodeValue = text.substring(0, sel.anchorOffset);
var dummy = document.createElement("i");
span.appendChild(dummy);
var pos = dummy.getBoundingClientRect();
sel.anchorNode.nodeValue = text;
span.removeChild(dummy);
pos contains the info of the position of the caret. Now you have to compare them with the rect infos about the span:
var rects = span.getClientRects();
for (var i = 0; i < rects.length; i++)
if (rects[i]].bottom === pos.bottom) break;
if (i < rects.length) {
for (var i = 0; i < spandata.length; i++) {
if (spandata[i].element === span) {
var line = spandata[i].iniRow + i;
break;
}
}
}
In the end, if line != null, it contains the line of the caret.
Man, that was complicated...
Let's say your div is in the el variable:
el.children.length; // Number of direct children
// You have one of the children in the "child" variable, to know its index:
[].indexOf.call( el.children, child ); // Index of child in el.children
I'm not mentioning the cross-browser issues there, but Array.prototype.indexOf is only available starting IE9 (so it works in all modern browsers).

Categories