There is one similar question, but I still not understand why I can't do the following:
var numLoaded = document.createElement('span')
numLoaded = document.createElement('span')
numLoaded.style= "color:red;font-weight:bold";
numLoaded.innerHTML = " Number of loaded results: "+0;
$("#resultsCounter").append(numLoaded)
for (var i = ((json.length)-1); i >= 0; i--) {
newDiv = document.createElement("div");
newDiv.id = +i+1;
newDiv.innerHTML = newDiv.innerHTML+"..."
numLoaded.innerHTML = " Number of loaded results: "+newDiv.id;
$("#resultsCounter").empty(); // should remove my span
$("#resultsCounter").append(numLoaded) // should add my span with new content
$("#results").prepend(newDiv)
}
After this all as output I see only last added element after whole cycle ends. During cycle iteration it appends to DOM no child, even if it is already created. I want to append always the same element <span> but in every iteration with updated number.
Why child element is added to DOM only after cycle ends? How to update it in cycle? Do I need to recreate that element after every loop iteration? It is way to speed up this process?
It's because you only create the element once, before the list. Then in the loop you are changing the innerHtml of the element, and adding it - but because it is the same element (the same JS object being referenced each time), it's effectively overwriting itself.
You just need to move these lines which create the element:
var numLoaded = document.createElement('span')
numLoaded = document.createElement('span')
numLoaded.style= "color:red;font-weight:bold";
numLoaded.innerHTML = " Number of loaded results: "+0;
inside the loop.
Related
why do the loop not writing expected output in the dom 15 times
I am trying to create an elemnt div 15 times with another div child
here is the code
for(let i=1;i<=15;i++){
let smalldiv=document.createElement("div").textContent=i;
let pr =document.createElement("div");
pr.textContent="product";
};
smalldiv.appendChild(pr);
let smalldiv=document.createElement("div").textContent=i;
doesn't set smalldiv to the DIV. When you write
let x = y = z;
it's equivalent to
y = z;
let x = y;
so you're setting smalldiv to the textContent that you assigned i to.
And even if you did set smalldiv to the DIV, you never append it to the DOM, so you wouldn't see the results.
Since you're appending pr to smalldiv after the loop, you're just appending the last pr. But that won't work either, because the scope of pr is the loop body, so you can't refer to it after the loop is done. You should append it inside the loop.
Don't use a DIV for numbered items, use an ordered list <ol>, with <li> elements within it.
let ol = document.createElement("ol");
for(let i=1;i<=15;i++){
let pr =document.createElement("li");
pr.textContent="product";
ol.appendChild(pr);
};
document.body.appendChild(ol);
First create the div smalldiv, then add the textContent.
Then you need to append the elements to the DOM using an element already in the DOM or append to the document.body.
for(let i=1;i<=15;i++){
// create the div and assign the variable
let smalldiv=document.createElement("div");
// set the textContent once created
smalldiv.textContent = `${i}. `;
// create new div 'pr'
let pr = document.createElement("span");
// assign its content
pr.textContent="product";
// append pr to smalldiv
smalldiv.append(pr);
// append smalldiv to the body
document.body.append(smalldiv);
};
I've got the following simplified code to a problem I was facing yesterday when I've asked this question:
Problem of JavaScript previous object inside an object is being overwritten [EDITED]
The simplified code is:
HTML
<div class="header"><button>click me to add new to DOM and Object</button></div>
<div class="list"></div>
Javascript
const list = document.querySelector(".list");
const button = document.querySelector('button');
const obj = {
counter: 1
}
function html(counter) {
return `<div>I am Item number ${obj.counter}</div>`;
}
function addItem() {
//add new element to the DOM
list.innerHTML += html(obj.counter);
//add new object to the object
obj[`ITEM-${obj.counter++}`] = [...list.querySelectorAll("div")].slice(-1)[0];
console.log(obj);
}
button.addEventListener("click", addItem);
The problem is:
I'm console.logging the "obj" to see it's content,
I want you to look at the console after some clicks on the button, you'll see this output
{counter: 6, ITEM-1: div, ITEM-2: div, ITEM-3: div, ITEM-4: div, …}
ITEM-1: div
ITEM-2: div
ITEM-3: div
ITEM-4: div
ITEM-5: div
counter: 6
__proto__: Object
The question is:
Why only the last item from inside the object is indicating the HTML code from inside the dom while the other previous items are no longer indicating the HTML elements?
to try what I'm trying to say:
please, inside the console, hover on the last item from the object, in my case, it's ITEM-5: div,
you'll see how the item on the DOM is being highlighted.
but now try to hover on previous items from inside the object, for example in my case
ITEM-1: div
it's not being highlighted on the DOM.
what is the problem?
Never use += on .innerHTML.
It is precisely equivalent to:
element.innerHTML = element.innerHTML + content
In other words it requires that the existing content of the element be serialised into HTML, and then you add your content to that string, and then the entire thing is re-assigned to the node (which has to be de-serialised back onto DOM format again), also forcing the previously-existing child nodes to be recreated.
When you are using innerHTML to add an element you are basically erasing all the elements and creating new ones. So when you create a reference to the element, the element is removed when the innerHTML is replaced.
Typically your question is asked as "Why do my click event handlers only work on the last element when I add to the list?"
Looking at the code you are doing
var current = list.innerHTML; // string of existing HTML
var newString = html(obj.counter); // String of new HTML
var updated = current + newString; // Combine to make a new string
list.innerHTML = updated; // redraw the DOM with the new string
When you change the innerHTML directly, it does not figure out what changes in the string, it just clears the "whiteboard" and redraws it all. If you do not what to redraw the whole element, you need to get smarter and instruct it to what is being added.
You should be appending a new element, not building it as a string.
const list = document.querySelector(".list");
const button = document.querySelector('button');
const obj = {
counter: 1
}
function elem(counter) {
var div = document.createElement("div");
div.innerHTML = `I am Item number ${obj.counter}`;
return div
}
function addItem() {
var newDiv = elem(obj.counter)
list.appendChild(newDiv);
obj[`ITEM-${obj.counter++}`] = newDiv;
console.log(obj);
}
button.addEventListener("click", addItem);
<div class="header"><button>click me to add new to DOM and Object</button></div>
<div class="list"></div>
I am very new to coding. Below is a piece of JS code i am struggling to understand:
var btnContainer = document.getElementbyId(“linkcontainer”);
var btns = btnContainer.getElementsbyClassName(“btn”);
for (var i = 0; i < btns.length; i++){
btns.addEventListener(“click”, function(){
var current = document.getElementsbyClassName(“active”);
current[0].className = current[0].className.replace(‘active’, “”);
this.className += ‘active’;
});}
What difference does the [i] make in
btns[i].AddEventListener??
What is it exactly and what if there was no “i” in between the brackets? Also current[0]. It’s probably a stupid question, but please help me understand.
First of all there are no stupid question but only stupid answers.
In your code you get a list of DOM elements stored in an array called 'btns', then you iterate it with a loop.
So btns[i] allow you to retrieves the elements at the i position (It's important to note that array start at 0 in Javascript).
Example:
var fruits = ['Apple', 'Banana'];
console.log(fruits[0])
console.log(fruits[1])
So if you don't use the [i] you will iterate on the array itself and not on the element stored in it.
As the name of the method getElementsByClassName suggests, this queries the DOM and returns an array like object that contain multiple elements with the class name that was specified.
btns - will be an array that contains one or more elements.
To access a specific element from the array, you access it using the index of the current iteration.
btns[1] - Gives you access to the 2nd element in the list.
addEventListener - is used to bind a event handler to a single element. You cannot directly use this on array of objects.
// query the DOM for element with id - linkcontainer
var btnContainer = document.getElementbyId(“linkcontainer”);
// query the DOM for elements with className - btn
// This can return multiple elements, so btns will be
// as array like object of elements
var btns = btnContainer.getElementsByClassName(“btn”);
// iterate over the array that was just queried for
for (var i = 0; i < btns.length; i++) {
// bind a click event for each element in the array
btns[i].addEventListener(“click”, function() {
// query the dom for elements with className - active
var current = document.getElementsByClassName(“active”);
// access the first element and replace the active class
current[0].className = current[0].className.replace(‘active’, “”);
// add the active class to the element that was clicked
this.className += ‘active’;
});
}
The way I see it you will have to remove the active class for all the elements instead of just the first entity. A slightly better way to improve this code would be is
var btnContainer = document.getElementbyId(“linkcontainer”);
var btns = btnContainer.getElementsByClassName(“btn”);
btns.forEach(function(btn) {
btn.addEventListener(“click”, function() {
// query the dom for elements with className - active
var current = document.getElementsByClassName(“active”);
current.forEach(function(elem) {
elem.classList.remove('active');
});
this.classList.add('active');
});
});
As the other posters have mentioned, your code var btns = btnContainer.getElementsbyClassName(“btn”); should return an array of DOM elements so in your for loop, btns[i] will retrieve the specific element at index i of btns as i goes from 0 to btns.length. Removing the i will retrieve the entire array on each iteration.
To your second question: current is exactly the same thing as btns, an array of DOM elements so current[0] will retrieve the first element in this array.
need some help over here.
I create and than, store DOM elements in a array.
Later, when i want to use them, they are like unusable, except for the last one.
Here is a realy simple code to illustrate :
http://jsfiddle.net/rd2nzk4L/
var list = new Array();
// first loop create and store elements
for (i = 1; i <= 5; i++) {
var html = '<div id="test-' + i + '" style="float: left; border: 2px solid black; width: 50px; height: 50px; margin: 5px;">' + i + '</div>';
document.getElementById('test').innerHTML += html;
var element = document.getElementById('test-' + i);
//console.log(element);
list.push(element);
}
// second loop use stored elements
for (index in list) {
//console.log(list[ index ]);
list[ index ].style.backgroundColor = 'yellow';
}
You can see only the last element became yellow.
I'll really appreciate if someone have an idea.
Thanks!
Setting the innerHTML of the container will recreate its entire DOM tree.
Therefore, all of the old elements from the previous iteration are no longer attached to the DOM.
You should only set innerHTML once.
because you aren't creating the elements, so they can't be found with the selector you are using. Try using document.createElement, then div.appendChild(element)
Each time you set the innerHTML of the container, it destroys all of the child elements and recreates them. This is a problem because now your array contains references to elements that no longer exist, apart from the final iteration.
The solution is to work with DOM elements, not raw HTML.
Fiddle
var list = [];
var container = document.getElementById("test");
// first loop create and store elements
for (var i = 1; i <= 5; i++) {
var element = document.createElement('div');
element.id = 'test-' + i;
element.className = 'mydiv';
element.appendChild(document.createTextNode(i));
container.appendChild(element);
list.push(element);
}
// second loop use stored elements
for (var x=0; x<list.length; x++) {
list[ x ].style.backgroundColor = 'yellow';
}
Side notes:
for..in can be used on arrays, but you need to use hasOwnProperty, or just use a basic for loop like above.
var list = \[\] is preferred to var list = new Array() – more info.
Remember to declare count variables like i using var to make them locally scoped, otherwise they will be scoped globally.
I am outputting the values of an array with a for loop by using innerHTML +=, in order to add to the contents of a current div- let's call it div1 (known as currentQuestions in the code).
The function which outputs the array values is to be used multiple times, as the values stored within the array change from user input. This means that div1 will have a growing list of output.
However the problem is that for each group of data iterated by the array, i need them to be stored together in their own div (within div1), separate from other groups generated by a different call of the same function.
they dont need to have unique IDs, but they are needed to call a function onclick which will affect only the div that is clicked.
This is what i have so far:
arrayLength = answers.length
for (var j = 0; j < arrayLength; j++)
{
document.getElementById('currentQuestions').innerHTML += answers[j] + '<br />'
}
As you can see, all i have is the for loop so far. I cant add a div to the innerHTML because then it will create a div for each iteration rather than one div for the full iteration of the array.
I'm out of ideas. Thoughts?
Create the div and attach the event handler before the loop, something like this:
var subdiv = document.createElement('div'), // Creates a new element to the DOM
arrayLength = answers.length;
subdiv.addEventListener('click', function () {...}); // Attach a click listener
for (var j = 0; j < arrayLength; j++) {
subdiv.innerHTML += answers[j] + '<br />'; // Add some content to newly-created DIV
}
document.getElementById('currentQuestions').appendChild(subdiv); // Append the newly-created element to the document.
Make your life easier and try jQuery...
This example would take the html within a div they clicked on and append it to the #currentQuestions div...
$('body').on('click', '.class_of_div_they_click_on', function(event) {
var div_content = $(this).html();
$("#currentQuestions").append(div_content + '<br>');
});