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>
Related
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
Let's say my code was something pretty simple like this:
let content = "";
for(let i=0; i<array.length; i++){
content+='<h1>array[i]</h1>';
}
document.getElementById('some_id').innerHTML = content;
I don't like the idea of putting HTML in my JavaScript code, but I don't know any other way of inserting elements into the DOM without using innerHTML, JQuery's html() method, or simply creating new DOM elements programmatically.
In the industry or for best practices, what's the best way to insert HTML elements from JavaScript?
Thanks in advance!
You can use a DOMParser and ES6 string literals:
const template = text => (
`
<div class="myClass">
<h1>${text}</h1>
</div>
`);
You can create a in memory Fragment:
const fragment = document.createDocumentFragment();
const parser = new DOMParser();
const newNode = parser.parseFromString(template('Hello'), 'text/html');
const els = newNode.documentElement.querySelectorAll('div');
for (let index = 0; index < els.length; index++) {
fragment.appendChild(els[index]);
}
parent.appendChild(fragment);
Since the document fragment is in memory and not part of the main DOM tree, appending children to it does not cause page reflow (computation of element's position and geometry). Historically, using document fragments could result in better performance.
Source: https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment
Basically you can use whatever template you want because it's just a function that return a string that you can feed into the parser.
Hope it helps
You can use the createElement() method
In an HTML document, the document.createElement() method creates the HTML element specified by tagName, or an HTMLUnknownElement if tagName isn't recognized.
Here is an example,
document.body.onload = addElement;
function addElement () {
// create a new div element
var newDiv = document.createElement("div");
// and give it some content
var newContent = document.createTextNode("Hi there and greetings!");
// add the text node to the newly created div
newDiv.appendChild(newContent);
// add the newly created element and its content into the DOM
var currentDiv = document.getElementById("div1");
document.body.insertBefore(newDiv, currentDiv);
}
<!DOCTYPE html>
<html>
<head>
<title>||Working with elements||</title>
</head>
<body>
<div id="div1">The text above has been created dynamically.</div>
</body>
</html>
A flexible and more faster (efficient) way to insert HTML elements using JavaScript's insertAdjacentHTML method. It allows you to specify exactly where to place the element. Possible position values are:
'beforebegin'
'afterbegin'
'beforeend'
'afterend'
Like this:
document.getElementById("some_id").insertAdjacentElement("afterbegin", content);
Here's a Fiddle example
Creating the element programmatically instead of via HTML should have the desired effect.
const parent = document.getElementById('some_id');
// clear the parent (borrowed from https://stackoverflow.com/questions/3955229/remove-all-child-elements-of-a-dom-node-in-javascript)
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
// loop through array and create new elements programmatically
for(let i=0; i<array.length; i++){
const newElem = document.createElement('h1');
newElem.innerText = array[i];
parentElement.appendChild(newElem);
}
Building this basic to-do list from scratch to try and teach myself Javascript. I found out through the API that there is a firstChild function that will target the first child of a parent node.
If I have..
<div class = "parentNode">
<div id = "i0">
TEXT HERE
</div>
<div id = "i1">
</div>
</div>
Then I have some button that is designated to the function:
document.getElementById('myButton').onclick = function () {
var parentNode = document.getElementById('parentNode');
var childNode = parentNode.firstChild.innerHTML;
alert('childNode');
}
Why would this not return TEXT HERE in the alert box?
There are a few things going on here. First, you are looking for an element that does not exist
var parentNode = document.getElementById('parentNode');
is looking for an id. This can be remedied by using an id="parentNode on the element, or you can query by class name instead using querySelectorMDN
var parentNode = document.querySelector('.parentNode');
Next, alert('childNode'); will always alert the string "childNode" and not the variable childNode so that needs to be alert(childNode).
Lastly, and perhaps most interesting, is that .firstChild will get the first childNode of the set of childNodes. This can be a #text node (which it is), becuase of the whitespace used between the end of the <div class = "parentNode"> and the beginning of <div id = "i0">.
As opposed to using .firstChild, you can use children[0] which will only look at elements. Here is a snippet that shows this behavior.
document.getElementById('myButton').onclick = function () {
var parentNode = document.querySelector('.parentNode');
var childNode = parentNode.children[0].innerHTML;
alert(childNode);
}
<button id="myButton" type="button">Click To Check Node</button>
<div class = "parentNode">
<div id = "i0">
TEXT HERE
</div>
<div id = "i1">
</div>
</div>
So I have the following HTML...
HTML:
<div id="col1">
<img src="1.jpg">
</div>
And I am implementing a HTML5 drag and drop feature where the inner html of col1 is changed for the dragged element's inner html - so basically the columns change their content.
I have another div (let's call that swap-text) where I want to change its text content depending on what image is presently inside col1.
This is why I want to figure out how I can obtain col1's img element's src attribute value through JavaScript so I can then write an if statement to change the content of the swap-text depending on which image is in col1.
I could add ID's to the img elements but then I still don't know how I would write the condition to check if say, img-id1 parent is col1.
Attempt(s):
var doc = document.getElementById("col1");
var children = null;
var imgEle;
//gets img node, but also got 1/2 text object(s)?
for (var i = 0; i < doc.childNodes.length; i++) {
children = doc.childNodes[i];
console.log(children);
}
//document.getElementById("img")
//children[1].getAttribute('src'); - cannot call method 'getAttribute' of undefined
//imgEle = doc.childNodes[0].getElementById('img'); - Object #<Text> has no method 'getElementById'
console.log(imgEle);
console.log(children);
This work fine pure javascript:
document.getElementById("col1").getElementsByTagName("img")[0].getAttribute("src");
var doc = document.getElementById("col1");
var img = document.getElementsByTagName('img')[0];
var imgParent = img.parentElement;
This is how you determine the elements parent/
I suggest you to use JQuery so you can simply use:
$("img").attr("id"); //Return the id of the img element
Check this:
var column = document.getElementById("col1");
var imgSrc = column.getElementsByTagName("img")[0].getAttribute("src");
Or just use the jQuery - it's simpler:
$('#col1 img').attr('src');
as you will only have one child node in col1 (the img), change the for loop.
var doc = document.getElementById("col1");
var children = null;
var imgEle;
//gets img node, but also got 1/2 text object(s)?
//for (var i = 0; i < doc.childNodes.length; i++) {
// children = doc.childNodes[i];
// console.log(children);
//}
childen = doc.childNodes[0];
// or children = doc.firstChild;
console.log(children);
//document.getElementById("img")
console.log(children.getAttribute('src')); - children is single object
//imgEle = doc.childNodes[0].getElementById('img'); - Object #<Text> has no method 'getElementById'
console.log(imgEle);
console.log(children);
<div id="parent">
<div id="child">
some-value
</div>
</div>
how do I get "some-value"?
I tried
var parent = document.getElementById("parent");
var child = parent.childNodes[0];
var childval = child.value;
document.getElementById("output").innerHTML=childval;
it outputs "undefined".
The value property only exists for form elements. If you want to get the content of any other elements, you can either use innerHTML [MDN] to get the content as HTML string, or textContent [MDN] resp. innerText [MSDN] to only get the text content without HTML tags.
childNodes [MDN] returns all child nodes, not only element nodes. That means, it also contains text nodes for example. The line break you have after <div id="parent"> is a text node as well. Hence, parent.childNodes[0] returns the text node which consists only of a line break.
If you want to get the first element node, you can either use children [MDN] (see browser compatibility), or iterate over the child nodes, testing what kind of node each of them is. 1 indicates an element node, 3 a text node:
var child = parent.firstChild;
while(child && child.nodeType !== 1) {
child = child.nextSibling;
}
There are also other ways to retrieve elements, e.g. with getElementsByTagName [MDN].
Or in your case, you can just use getElementById [MDN] to get a reference to both of the elements.
The problem is that parent <div> actuially has three children: a TextNode containing a new line after parent opening tag, the actual child <div> and yet another TextNode with newline after closing child tag. But hard-coding second item is a bad idea:
var parent = document.getElementById("parent");
console.info(parent.childNodes.length);
var child = parent.childNodes[1];
var childval = child.innerHTML;
I would suggest iterating over children and finding the actual child or using
parent.getElementsByTagName('div')
shorthand.
That's one of the reasons why people love jQuery so much:
$('#parent div').text()
var parent = document.getElementById("parent");
var child = parent.children[0];
var childVal = child.innerHTML;
document.getElementById("output").innerHTML = childVal;
DEMO : http://jsfiddle.net/bcqVC/2/
document.getElementById("output").innerHTML = document.getElementById("child").innerHTML;
This will solve your problem.
Using your way of approach try as shown below
var parent = document.getElementById("parent");
var child = parent.childNodes[0];
var childval = child.innerHTML;
document.getElementById("outPut").innerHTML=childval;
This will also solve your problem
To get all the <div> elements you can use:
var div_val=prompt("Enter a div to Get the Child Elements","");
var div_ele=document.getElementById(div_val).childNodes;
for (var i=0, max=div_ele.length; i < max; i++) {
alert(div_ele[i]); //All your Div Elements
}
try this way by this pointer.
var childs = document.getElementById('myDropdown').children; //returns a HTMLCollection
for (var indx = 0; indx < childs.length; indx++) {
// iterate over it
childs[indx].onclick = function() {
// attach event listener On Symbole Dive THIS .
this.style.color = "#ff0000";
// add to note form the symbole .
document.getElementById("Note_form").value += this.innerHTML;
}
}
<div class="dropdown">
<div id="myDropdown" class="dropdown-content">
<div>♥</div>
<div>☺</div>
<div>π</div>
<div>•</div>
<div>Σ</div>
<div>°</div>
<div>Ω</div>
<div>∞</div>
<div>×</div>
<div>÷</div>
<div>≥</div>
<div>≤</div>
<div>≠</div>
<div>®</div>
<div>©</div>
<div>¥</div>
<div>£</div>
<div>€</div>
</div>
</div>
<textarea id="Note_form" class="copy_erea" placeholder="The Content.." oninput="note_Edite(this.value);"></textarea>