I am unable to append multiple times using the createdocumentfragment JS call - javascript

const btn = document.querySelector(".test");
btn.addEventListener("click", () => {
a1 = document.createElement('h5');
a1.className = "bluecolor";
a1.innerHTML = 'Blue updated';
console.log(a1); //console log output is <h5 class="first">Blue updated.</h5>
document.getElementById('position').innerText = null; //clear the position
fragment = document.createDocumentFragment(); //create fragment
fragment.append(a1); //append a1 element to the fragment,works 1st time only
fragment.append(a1); //append a1 element to the fragment
fragment.append(a1); //append a1 element to the fragment
fragment.append(a1); //append a1 element to the fragment
fragment.append(a1); //append a1 element to the fragment
document.getElementById('position').append(fragment); //append the fragment to the DOM tree
});
.first,
.test {
color: bluecolor;
}
<h5 id="position">Text to be replaced</h5>
<button class="test">blue</button>
Upon clicking the 'blue' button, I wanna display the text 'Blue color updated' 5 times at once using the createdocumentfragmentAPI but the text 'Blue color updated' updates 1 time only even though I am trying to use the below process mentioned in the createdocumentfragment docs:
**The usual use case is to create the document fragment, append elements to the document fragment and then append the document fragment to the DOM tree. In the DOM tree, the document fragment is replaced by all its children.
**
so where am I am going conceptually wrong , please explain

This is the way the DOM works. If you append an existing element that is already in the DOM (or in this case a DOM fragment) in another place, the element is moved, not copied.
You would need to create new elements if you wish to insert them in a different place.

Other are already explain issue.\
Use cloneNode property to clone your existing element.
const btn = document.querySelector(".test");
btn.addEventListener("click", () => {
a1 = document.createElement('h5');
a1.className = "bluecolor";
a1.innerHTML = 'Blue updated';
console.log(a1); //console log output is <h5 class="first">Blue updated.</h5>
document.getElementById('position').innerText = null; //clear the position
fragment = document.createDocumentFragment(); //create fragment
fragment.append(a1.cloneNode(true)); //append a1 element to the fragment,works 1st time only
fragment.append(a1.cloneNode(true)); //append a1 element to the fragment
fragment.append(a1.cloneNode(true)); //append a1 element to the fragment
fragment.append(a1.cloneNode(true)); //append a1 element to the fragment
fragment.append(a1.cloneNode(true)); //append a1 element to the fragment
document.getElementById('position').append(fragment); //append the fragment to the DOM tree
});
<h5 id="position">Text to be replaced</h5>
<button class="test">blue</button>

Related

Append div multiple times using JavaScript on DOM Loaded [duplicate]

This question already has an answer here:
Append Div with Multiple Child Divs Using For Loop
(1 answer)
Closed 1 year ago.
I want to append the HTML child_element div multiple times as defined on variables inside the parent_element using Javascript on DOM Load.
Desire Output:
<div class="parent_element">
<div class = "child_element">
<div class = "child_element">
<div class = "child_element">
<div class = "child_element">
<div class = "child_element">
</div>
You can create a child node object and append it to the parent node in loop. Since you have multiple child nodes to be appended you can use DocumentFragment
const parentNode = document.createElement('div');
parentNode.classList.add('parent_element');
const childNode = document.createElement('div');
childNode.classList.add('child_element');
const fragment = new DocumentFragment();
for(let i=0; i<[*no_of_times_you_want_child_node*]; i++) {
fragment.appendChild(childNode.cloneNode(true));
}
// finally append dom fragment to parent
parentNode.appendChild(fragment);
Assuming that you want the number of children to be defined by an attribute "variables inside the parent_element"
<div class="parent" children="5"></div>
<script>
const parentEl = document.querySelector(".parent");
const numOfChildren = +parentEl.getAttribute("children");
const fragment = new DocumentFragment();
for (let i=0; i<numOfChildren; i++) {
const childEl = document.createElement("div");
childEl.classList.add("child");
fragment.appendChild(childEl);
}
parentEl.append(fragment);
</script>
The basic process is:
Get a reference to the parent element using the class selector
Retrieve the number of children you want from the attribute named children. This is a string value so the + will convert it to a number
Loop through the creation of a new element on the DOM adding the desired class name before appending the child.
Edit: As per pilchard's suggestion I've merged in DocumentFragment from abhishek khandait's answer.
You can dynamically add a new div element using jquery.
<script>
function addNewDivElement() {
$("#parent_element").append('<div class = "child_element">')
}
</script>
the function addNewDivElement can be called on click of a button. something like below:
<button onclick="addNewDivElement()">
Add
</button>

make a DOM element's content be the one of a document fragment

I am trying to insert into a DOM element the content of a document fragment (in pure javascript). The working principle is this:
var a = document.getElementById("a"),
b = document.getElementById("b");
now i place the content of "a" into a document fragment, using a template element
var content = document.createElement("template");
content.innerHTML = a.innerHTML;
content = content.content.cloneNode(true);
now i would like to replace the content of b with the content of content. I tried with a simple b.innerHTML = content.innerHTML;, but it seems like if document fragments doesn't have innerHTML property.
Is this possible to do?
Note: i know this is totally an ineffective way to do the task of making b.innerHTML = a.innerHTML, but obviously this is just a simplification of a bigger task i am managing to do.
You need to create "clones" and by using the template content property you can then use the innerHTML of a and b into your fragments.
Example:
const a = document.getElementById("a"),
b = document.getElementById("b");
// note template will only be parsed, to render it use js...
function initTemplate() {
const container = document.getElementById("container");
const template = document.getElementById("t");
// create a first clone with the innerHTML of a...
const firstClone = template.content.cloneNode(true);
firstClone.textContent = a.innerHTML;
// create a second clone with the innerHTML of b...
const secondClone = template.content.cloneNode(true);
secondClone.textContent = b.innerHTML;
// append to the document
container.appendChild(firstClone);
container.appendChild(secondClone);
}
<p id="a">Paragraph A</p>
<p id="b">Paragraph B</p>
<button onclick="initTemplate()">Init Template</button>
<br>
<div id="container"></div>
<template id="t">
</template>
If you want to check if your browser supports the HTML template element, do something like this:
if ("content" in document.createElement("template") {
// clone the elements as above and append them to the document
}
Mozilla Docs and Mozilla Docs

Is it possible to loop through multiple elements and then add another element to each of the selected elements?

For example, can I put <h1> inside two separate <div> elements using a loop?
I know you can just use the function to append the element but I was wondering if you can use a loop to achieve this.
I have tried this but it only selects the first div.
HTML
<div id="event1" class="yellow"></div>
<div id="event2" class="blue"></div>
JAVASCRIPT
function myElement(tag, msg) {
var h1 = document.createElement(tag);
var text = document.createTextNode(msg);
h1.appendChild(text);
return h1;
}
var eventHolder = document.createElement("div");
var event = document.getElementsByTagName("div");
for (var i = 0; i < event.length; i++) {
eventHolder.appendChild(myElement("h1", "events"));
document.getElementsByTagName("div")[i].appendChild(eventHolder);
}
The document.getElementsByTagName("div"); will be a live collection of every div in the document. When you insert another div, its length will be increased. The error that results is
Uncaught HierarchyRequestError: Failed to execute 'appendChild' on 'Node': The new child element contains the parent.
Live collections are weird. Loop over and append to elements of a static collection instead:
function myElement(tag, msg) {
var h1 = document.createElement(tag);
var text = document.createTextNode(msg);
h1.appendChild(text);
return h1;
}
var eventHolder = document.createElement("div");
var event = document.querySelectorAll("div");
for (var i = 0; i < event.length; i++) {
eventHolder.appendChild(myElement("h1", "events"));
event[i].appendChild(eventHolder);
}
<div id="event1" class="yellow"></div>
<div id="event2" class="blue"></div>
A loop can be used to append elements to multiple tags,
If you check your console you should get Uncaught DOMException: Failed to execute 'appendChild' on 'Node': The new child element contains the parent.
var eventHolder = document.createElement("div"); This is a div, this hasn't been attached to the DOM yet.
var event = document.getElementsByTagName("div"); This is an array of all divs currently attached to the DOM - In our case 2.
eventHolder.appendChild(myElement("h1", "events")); Here you append a newly created h1 element to the earlier created div eventHolder
document.getElementsByTagName("div")[i].appendChild(eventHolder); This line retrieves all the divs in the DOM afresh and appends the newly created element based on the index
The Problem
On the first loop we have 2 divs in the DOM, the index is at 0 so it appends a new element to first one
Note that you are appending a div eventHolder and so on the second loop it fetches all divs again (now 3) which includes the new div, and tries to append eventHolder again
The solution would be to stop fetching the divs in the DOM on every loop, so if there are (2) divs in the DOM only those divs will be processed in the loop this means using the events variable
The answer by #Snow is correct, this is just an explanation

How to append a child to one of the elements in a variable by part of the class name and replace the parent?

I have a JS variable var e which is created by document.createElement method. I want to append a new element to an element inside the e which has jackson in its class name (full class name is large button 1 jackson). Also, how can I replace the large button 1 jackson element with the updated element afterwards? Would you suggest a solution?
Here is an example using querySelector
// container element
var e = document.createElement('div');
// child element with class 'large button 1 jackson'
e.innerHTML = '<div class="large button 1 jackson">some text</div>';
// insert the container element
document.body.appendChild(e);
// new element
var newElem = document.createElement('textarea');
// find a element with jackson class (using .jackson as selector)
var jackson = e.querySelector('.jackson');
// insert new element
jackson.appendChild(newElem);

refresh html while dynamically adding elements

I've got a bit of javascript that dynamically adds elements to my page. The problem is that there are hundreds of elements to create on any given run, and although it takes less than a second to load a single element, the whole page may take 30 seconds or more to load completely, then everything suddenly springs up onto the page. My question is: how can I update the page so that my dynamically created element will be displayed as soon as it is created?
var newDiv = document.createElement('div');
for (var val in array) {
var newCanvas = document.createElement('div');
newCanvas.className = "graph";
newDiv.appendChild(newCanvas);
drawGraph(val, newCanvas); //adds a bunch of elements to newCanvas
addTitle(val, newCanvas); //adds another
addDescription(val, newCanvas); //adds another
}
document.body.appendChild(newDiv);
It is extremely inefficient to dynamically add hundreds of elements to the DOM one at a time. Every time you add a single visible element to the DOM you force a reflow of the entire DOM tree which is followed by a repaint to the screen.
You should use JavaScript to create a DOM fragment (e.g. a div element) to which you can append new DOM elements. Once you have all of the new elements you can wholesale add them all by transferring the children of that fragment to the containing DOM element in the live DOM tree.
The following is an example of a function that creates a DOM element with a set of specified attributes and optional child elements. After an element and its children are assigned to the variable myDiv that element is appended to the document's body.
function dom(tag, attributes) {
var el, key, children, child;
el = document.createElement(tag);
for (key in attributes) {
if (attributes.hasOwnProperty(key)) {
el[key] = attributes[key];
}
}
for (i = 2, l = arguments.length; i < l; i++) {
child = arguments[i];
if (child.nodeType == 1 || child.nodeType == 3) {
el.appendChild(child);
}
}
return el;
}
var myDiv = dom(
'div',
{ id: 'myDiv', className: 'container' },
dom(
'p',
{ className: 'firstParagraph' },
document.createTextNode('If you enjoy this movie, '),
dom(
'a',
{ href: 'http://www.amazon.com', title: 'Buy this movie at Amazon.com!' },
document.createTextNode('buy it at Amazon.com')
),
document.createTextNode('!')
),
dom(
'p',
{},
document.createTextNode('The quick brown fox jumps over the lazy dog.')
)
);
document.body.appendChild(myDiv);
Put all the element loading after the DOM is constructed.
i.e use
$(document).ready(function(){
// induvidual elements loadings
});
The $ sign denotes Jquery. For using jquery, add the script block.
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
This way the basic structure will load completely and individual parts may take its own time.

Categories

Resources