Javascript efficiency improvement on appendChild Method - javascript

I want to alter the following Java script to make it more efficient
for(var i = 0; i < 1000; i += 1){
var el = document.createElement('div');
el.appendChild(document.createTextNode('Node ' + (i + 1)));
document.getElementById('nodeHolder').appendChild(el);
}
Ideally it would be grateful if the reason behind it could be provided.
Any idea would be very much appreciated.

Create a document fragment and append to that, then do a single append for the entire set.
var frag = document.createDocumentFragment();
for(var i = 0; i < 1000; i += 1){
var el = document.createElement('div');
el.appendChild(document.createTextNode('Node ' + (i + 1)));
frag.appendChild(el);
}
document.getElementById('nodeHolder').appendChild( frag );
Now your getElementById only needs to run once, and the DOM only needs to update once.
The document fragment is a generic container. When appending it to the DOM, the container just disappears, and only its content is appended.
You can condense the code a bit if you like:
Example: http://jsfiddle.net/7hagb/
var frag = document.createDocumentFragment();
for(var i = 0; i < 1000; i += 1){
frag.appendChild(document.createElement('div'))
.appendChild(document.createTextNode('Node ' + (i + 1)));
}
document.getElementById('nodeHolder').appendChild( frag );
Additionally, a very minor optimization would be to get rid of the i + 1, and modify the for loop to provide the values you want.
Example: http://jsfiddle.net/7hagb/1/
var frag = document.createDocumentFragment();
for(var i = 1; i <= 1000; i += 1){
frag.appendChild(document.createElement('div'))
.appendChild(document.createTextNode('Node ' + i));
}
document.getElementById('nodeHolder').appendChild( frag );

You can use DocumentFragment, a lightweight node container which prevents DOM from refreshing and reflowing when you append nodes on it.
var nodeHolder = document.createElement('div'),
fragment = document.createDocumentFragment();
for (var i = 0; i < 1000; i ++ ) {
var el = document.createElement('div');
el.innerHTML = 'Node ' + (i + 1);
fragment.appendChild(el);
}
nodeHolder.appendChild(fragment);

do not use DOM, just use html instead.
for example instead of createElement use
abc = ""
for(...){
abc += "<div>Text " + i + "</div>";
}
and then append to the target.
It is ugly, I agree, but should run much faster

Related

get two Elements by Id in same js function [duplicate]

My question is:
Is that possible to add the same element without rewriting the same variable.
I am creating a slider, and i need to append a div with a class slide-el into block slider.
Here is a part of code
var body, html, sliderBody, btnLeft, btnRight, i, parts, vHeight, vWidth;
//Variable definitions
var i = 0,
parts = 3,
//Main html elements
body = document.body,
html = document.element,
//viewport Height and Width
vHeight = window.innerHeight,
vWidth = window.innerWidth,
sliderBody = _id("slider"),
btnLeft = _id("btn-left"),
btnRight = _id("btn-right"),
urls = ["http://www.wallpapereast.com/static/images/pier_1080.jpg",
"http://www.wallpapereast.com/static/images/pier_1080.jpg",
"http://www.wallpapereast.com/static/images/pier_1080.jpg",
"http://www.wallpapereast.com/static/images/pier_1080.jpg"];
slide = _createEl("div");
slide.className += "slide-el";
function _id(el){
return document.getElementById(""+ el +"");
}
function _createEl(el){
return document.createElement(""+ el +"");
}
window.onload = function(){
slideLayout();
}
function slideLayout(){
for(var i=0; i < urls.length; i++){
sliderBody.appendChild(slide);
}
}
The problem is that I can't append the same element that many times. It just creates one element instead of 4.
For you to understand better I made a fiddle:
https://jsfiddle.net/ud7dvn3z/
appendChild will remove the node from wherever it is before appending it to its new location, so you need to make copies of the node instead. You can use cloneNode for that. The true makes cloneNode perform a deep clone, i.e. with all its child nodes.
for(var i = 0; i < urls.length; i++){
sliderBody.appendChild(slide.cloneNode(true));
}
Okey guys! I found an answer. I have to put
slide = _createEl("div");
slide.className += "slide-el";
into for loop.
Now it looks like this:
for(var i=0; i < urls.length; i++){
slide = _createEl("div");
slide.className += "slide-el";
sliderBody.appendChild(slide);
}

create multiple divs using a for loop

This is a really simple question but I don't know why it doesn't work.
I have an array with 3 items inside. And I have a container which I would like to insert a number of divs based on the number of items in my array. I used a for loop for this but it is only creating one div. Should it not create 3?
for (var i = 0; i < array.length; i++) {
var container = document.getElementById("container");
container.innerHTML = '<div class="box"></div>';
}
here is a fiddle to demonstrate further fiddle
Move container out of the loop, it is not required inside it.
Append the innerHTML in each iteration.
var container = document.getElementById("container");
for (var i = 0; i < array.length; i++) {
container.innerHTML += '<div class="box"></div>';
}
Edit:
Thanks Canon, for your comments. I also wanted to suggest the same approach as yours, but I got busy in some other work after posting the answer [No excuses :)] Updating the answer:
var htmlElements = "";
for (var i = 0; i < array.length; i++) {
htmlElements += '<div class="box"></div>';
}
var container = document.getElementById("container");
container.innerHTML = htmlElements;
This may look like involving more lines of code but this will be more efficient and less error-prone than the previous solution.
Replace = to +=
As per the #canon comment, edited answer are below
var innerHTMLString = "";
forloop {
innerHTMLString += '<div class="box"></div>';
}
document.getElementById("htmlElements").innerHTML = innerHTMLString
Replace this
container.innerHTML = '<div class="box"></div>';
with this
container.innerHTML += '<div class="box"></div>';
If you want to create more than one, you must call createElement more than once.
d=document.createElement("div");
line into the j loop.
If you call appendChild passing in an element that's already in the DOM, it's moved, not copied.
window.onload=function()
{
var i=0;
var j=0;
for (i=1; i<=8; i++)
{
for (j=1; j<=8; j++)
{
if ((i%2!=0 && j%2==0)||(i%2==0 && j%2!=0))
{
var d=document.createElement("div");
document.body.appendChild(d);
d.className="black";
}
else
{
var d=document.createElement("div");
document.body.appendChild(d);
d.className="white";
}
}
}
}
Javascript Method -
var container = document.getElementById("container");
for (var i = 0; i < array.length; i++) {
container.innerHTML += '<div class="box"></div>';
}
jQuery Method -
foreach(array as value){
$("#container").append('<div class="box"></div>')
}
For further references; what about this approach? :)
HTML:
<div class="particles">
<div class="parts"></div>
</div>
JavaScript:
// Cloning divs where particles go in order not to put 300 of them in the markup :)
const node = document.querySelector(".parts");
[...Array(300)].forEach(_ =>
node.parentNode.insertBefore(node.cloneNode(true), node)
);

Div's are being generated dynamically and even the (obj.search) fetches the data but nothing is being displayed in it. How do i display the data?

JS doesn't display the output
for (var i = 0; i < obj.Search.length; i++){
var divTag = document.createElement("div");
divTag.id = "div"+i;
divTag.className = "list";
document.getElementById('div'+i).innerHTML+=obj.Search[i].Title+obj.Search[i].Year;
}
Image here
You missed adding the newly created element to the DOM. Example:
document.getElementById("yourDivContainer").appendChild(divTag);
Fiddle:
http://jsfiddle.net/mbpfgm49/
You need to append your div tags to some element (e.g: body), to make text appear on page
// Let's create some sample data
var obj = {
Search: []
}
var currentYear = (new Date).getFullYear();
for (var i = currentYear - 10; i <= currentYear; i++) {
obj.Search.push({
Title: 'Test',
Year: i
})
}
// Here goes your code fixed
for (var i = 0; i < obj.Search.length; i++) {
var divTag = document.createElement("div");
divTag.id = "div" + i;
divTag.className = "list";
divTag.innerHTML = obj.Search[i].Title + ' ' + obj.Search[i].Year;
document.body.appendChild(divTag);
}
Yes, you have to add the element to the DOM.
More basically, it is an anti-pattern to construct IDs for elements and use those as the primary means for referring to elements, by means of calling getElementById at every turn. I guess this approach is one of the many lingering after-effects of the jQuery epidemic.
Instead, keep references to elements directly in JS where possible, and use them directly:
for (var i = 0; i < obj.Search.length; i++){
var divTag = document.createElement("div");
divTag.className = "list";
parent.appendChild(divTag);
^^^^^^^^^^^^^^^^^^^^^^^^^^ INSERT ELEMENT
divTag.innerHTML+=obj.Search[i].Title+obj.Search[i].Year;
^^^^^^ REFER TO ELEMENT DIRECTLY
}
To be absolutely pedantically correct, what you are creating is not a "tag", it's an "element". The element is the DOM object. The "tag" is the div which characterizes the element type.

Javascript - Add images

I have some images (image1, image2, image3 ..etc. ) and I will add those images to each cell seperately. I found a code to insert the images.
document.getElementById("cell1").innerHTML = "<img src='image1.png'>";
Now, Can someone help me to put above code in a loop in order to avoid to write same code for each image ?
I have tried below code but it does not work. Probably there is a problem with quotes. Or is there a better way to insert multiple images to each cells ?
for (x=0; x=10; x++) {
document.getElementById("'cell" + x + "'").innerHTML = "<img src=" + "' + x + ".png'>"; }
for (x=0; x=10; x++) {
document.getElementById("cell" + x).innerHTML = "<img src='image" + x + ".png' />";
}
for (x=0; x=10; x++) {
var img = new Image();
img.src = 'image' + x + '.png';
document.getElementById('cell' + x).appendChild(img);
}
As you may have noticed creating elements from html strings can get really messy really quick.
Its often a a better idea to use document.createElement to create the elements and then manipulate the properties of the element.
img = document.createElement("img");
img.src = "image" + i + ".png"; // image1.png ... etc
Another very useful technique is using document fragments to create ad-hoc collections of elements before we actually attach them to the real document or elements.
frag = document.createDocumentFragment();
frag.appendChild(img);
targetNode.appendChild(fragment); // attach all the images in the fragment
This is good for performance since actually touching the DOM is slow - we don't want to do it over and over in a loop.
Lets take these two techniques and create a function which creates img elements
function createImages(n){
var i, frag, img;
frag = document.createDocumentFragment();
for (i = 0; i < n; i ++) {
img = document.createElement("img");
img.src = "image" + i + ".png"; // image1.png ... etc
frag.appendChild(img);
}
return frag;
}
We could use this function to attach images to each cell in table
var table = document.getElementById('test'),
cells = table.getElementsByTagName('td');
(function(){
var i,
len = cells.length,
images = createImages(3);
for (i = 0; i < len; i++) {
cells[i].appendChild( images.cloneNode(true) );
}
}());

javascript appenchild

for(var i=0; i<myJSONObject.model.length; i++){
var create_div = document.createElement('div');
create_div.id = 'model_id'+i;
create_div.innerHTML = myJSONObject.model[i].model_name;
var assign_innerHTML = create_div.innerHTML;
var create_anchor = document.createElement('a');
document.getElementById('models').appendChild(create_div);
document.getElementById(create_div.id).appendChild(create_anchor);
}
for ex the myJSONObject.model.length is 2
the output is like this
<div id = 'model_id0'>XXXXX<a> </a></div>
<div id = 'model_id1'>XXXXX<a> </a></div> */
but instead of above the output sholud be like this
<div id = model_id0> <a> xxxxxx</a></div>
<div id = model_id1> <a> xxxxxx</a></div>
how to append it inside of the innerhtml
any one plz reply !!!!
two suggestions:
1.) instead of assigning innerHTML to model_idx div assign the model name to its child a. and 2nd instead of appending it to DOM in every loop do it after completing the loop as to minimize frequent the DOM Update ie by:
objContainer = document.createElement('div');
for(....)
{
var create_div = document.createElement('div');
create_div.id = 'model_id'+i;
var create_anchor = document.createElement('a');
create_anchor.innerHTML = myJSONObject.model[i].model_name;
create_div.appendChild(create_anchor);
objContainer.appendChild(create_div);
}
document.getElementById('models').appendChild(objContainer);
I would go along the lines of:
var i = 0,
m = myJSONObject.model,
l = m.length,
models = document.getElementById("models");
for(; i < j; i++) {
var model = m[i];
var create_div = document.createElement("div");
create_div.id = "model_id" + i;
create_div.innerHTML = "<a>" + model.model_name + "</a>";
models.appendChild(create_div);
}
Unless you specifically need to do something to the anchor itself (other than set its innerHTML), there's no need to create a reference to an element for it. If you do need to do something specific to that anchor, then in that case have this, instead:
EDIT: As per your comment, you DO want to do something to the anchor, so go with this (now updated) option - assuming the anchor will always be a child of the div that has the ID you require. The reason "model_id" + i is being put in as a string is because that is exactly what is being passed into the HTML - the document has no clue what "i" is outside of javascript:
var i = 0,
m = myJSONObject.model,
l = m.length,
models = document.getElementById("models");
for(; i < j; i++) {
var model = m[i];
var create_div = document.createElement("div");
var create_anchor = document.createElement("a");
create_div.id = "model_id" + i;
create_anchor.innerHTML = model.model_name;
if(window.addEventListener) {
create_anchor.addEventListener("click", function() {
getModelData(1, this.parentNode.id);
}, false);
} else {
create_anchor.attachEvent("onclick", function() {
getModelData(1, this.parentNode.id);
});
}
create_div.appendChild(create_anchor);
models.appendChild(create_div);
}

Categories