Append method not appending to all elements - javascript

I have created my own JS library. In that i am trying to define append method like this:
append: function (els) {
var elChild = document.createElement('span');
elChild.innerHTML = els;
for(i = 0; i < this.length; i++){
this[i].appendChild(elChild);
}
}
Now i am calling this append method in my script tag of HTML page like this:
<body>
<h1 class="first_heading">hello</h1>
<h1 class="second_heading">hi</h1>
<button>Test Me</button>
</body>
<script>
dome.get('h1').append('<p>some text</p>');
</script>
But the problem is all h1 tags not appending the paragraph text. Only last h1 is appending paragraph text. Any solution?

https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild:
The Node.appendChild() method adds a node to the end of the list of children of a specified parent node. If the given child is a reference to an existing node in the document, appendChild() moves it from its current position to the new position
In other words, the same node can't appear in multiple places in a document. You have to call document.createElement('span') separately for each child you want to create.

As mentioned this this corresponds to the object in scope. In this scenario, it is the window object. Here is a simple way to append the string to all headers
function append(tagname, text) {
// get all tag names
all_t = document.getElementsByTagName(tagname);
// loop through and append the string to the inner html of each tag
for (var x = 0; x < all_t.length; ++x) {
all_t[x].innerHTML += text
}
}
append('h1', '<p>some text</p>')
<h1 class="first_heading">hello</h1>
<h1 class="second_heading">hi</h1>
<button id="b">Test Me</button>

Related

Changing HTML in JavaScript without innerHTML

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

InnerHTML creates new nodes (new references) each time

I'm creating a document object via DOMImplementation.createHTMLDocument() and i'm inserting some html with the innerHTML property.
after that i'm appending the nodes to the realdom like this:
function appenderController (nodes,target,uid){
for(let i = 0 ; i < nodes.children.length ; i++) {
if(nodes.children[i].children.length > 0){
if(nodes.nodeType === "9"){
appenderController(nodes.children[i],target);
continue;
}
let realnode = appender(target, nodes.children[i]);
appenderController(nodes.children[i],realnode);
}
if (uid && nodes.children[i].nodeName.toLowerCase() === uid) {
nodes.children[i].remove();
return;
}
appender(target, nodes.children[i]);
}
}
in some cases i'm adding more html to our document and because innerhtml creates the entire document again so i'm also adding special attribute to each node to keep track on which nodes i've already appended.
the problem arises when i'm calling appenderController recursively with nodes = fakedocument.body but inside another function i'm updating the innerhtml for our fakedocument and on the next iteration of appenderController it will continue iterating on the old fakedocument.body , how can i keep the reference to my fake document even if i use innerhtml and update the nodes again
EXAMPLE:
var html='
<html>
<head>
</head>
<body>
<div id="somediv1"></div>
</body>
</html>'
;
var dom = document.implementation.createHTMLDocument();
dom.documentElement.innerHTML = html;
var body = dom.body;
var html2='
<html>
<head>
</head>
<body>
<div id="somediv1"></div>
<div id="somediv2"></div>
</body>
</html>'
;
dom.documentElement.innerHTML = html2;
now if we look at "body" var we will not have "somediv2" , that's exactly what's happening in my function , in some point i'm updating the innerhtml of my fake document but the "appenderController" continues to iterate with the old nodes
Assign each element a unique ID. Then access elements by ID, both on the real DOM, and the temporary one.
Do not store references to elements, store their IDs instead.
—
You can also import nodes from one DOM into another instead of replacing the entire tree using innerHTML. That approach will not interfer with iterating parent elements.
https://developer.mozilla.org/en-US/docs/Web/API/Document/importNode

Change only the text of an anchor javascript

I'm trying to write a simple script which will change the text of a number of anchors on a page. I'm quite new to Javascript and I'm able to change the anchors but it changes the whole tag including removing the href.
How do I edit just the text only without affecting the href?
<body>
<div class="loop-add-to-cart">
Add to basket
<div class="wpd-buttons-wrap-simple" data-id="11544">
Design from blank
</div>
</div>
<script>
function buybuttons() {
var buybuttons = document.getElementsByClassName('wpd-buttons-wrap-simple');
for(var i = 0; i < buybuttons.length; i++){
buybuttons[i].innerHTML="Test";
};
}
buybuttons();
</script>
</body>
You can use a query selector to get all a tags inside an element with a class of wpd-buttons-wrap-simple:
document.querySelectorAll('.wpd-buttons-wrap-simple a');
You can then set the textContent or innerHTML of the link.
<body>
<div class="loop-add-to-cart">
Add to basket
<div class="wpd-buttons-wrap-simple" data-id="11544">
Design from blank
</div>
</div>
<script>
function buybuttons() {
var buybuttons = document.querySelectorAll('.wpd-buttons-wrap-simple a');
for(var i = 0; i < buybuttons.length; i++){
buybuttons[i].textContent = "Test";
};
}
buybuttons();
</script>
</body>
Using 'querySelectorAll' you can get the element the class and the element inside as below:
document.querySelectorAll('.wpd-buttons-wrap-simple > a')
function buybuttons() {
var buybuttons = document.querySelectorAll('.wpd-buttons-wrap-simple a');
for(var i = 0; i < buybuttons.length; i++){
buybuttons[i].innerHTML="Test";
};
}
buybuttons();
You are currently overwriting the innerHTML of the div element, but you are looking for the anchor element inside of the div.
Use document.querySelectorAll to get all of them, or document.querySelector to only get the first.

Get all tag nodes inside another tag recursively

I have an html document consists of a <div id = "main">. Inside this div may be several levels of nodes, without a precise structure because is the user who creates the document content.
I wanto use a JavaScript function that returns all nodes within div id = "main". Any tag is, taking into account that there may be different levels of children.
For now I have this function that returns all tags, even those outside to div id = "main":
function getNodes() {
var all = document.getElementsByTagName("*");
for (var elem = 0; elem < all.length; elem++) {
//do something..
}
}
As such this document:
<div id="main">
<h1>bla bla</h1>
<p>
<b>text text text </b> text text <i>text</i>.
<img src=".."></img>
</p>
<div>
<p></p>
<p></p>
</div>
<p>..</p>
</div>
The function getNodes would return an array of object nodes (I don't know how to represent it, so I list them):
[h1, p, b, i, img, div, p, p, p]
Thank you
Use document.querySelectorAll. It returns a NodeList, not an array, but you can loop over it in the same way:
function getNodes() {
var all = document.querySelectorAll("#main *");
for (var elem = 0; elem < all.length; elem++) {
//do something..
}
}
http://jsfiddle.net/suuja4L5/
Just get the parent element and then get the descendents just as you did:
var mainDiv = document.getElementById("main");
mainDiv.getElementsByTagName("*")
if you want all child of <div id="main">,then use the following :
var children = document.querySelector("#main").children;

replace specific tag name javascript

I want to know if we can change tag name in a tag rather than its content. i have this content
< wns id="93" onclick="wish(id)">...< /wns>
in wish function i want to change it to
< lmn id="93" onclick="wish(id)">...< /lmn>
i tried this way
document.getElementById("99").innerHTML =document.getElementById("99").replace(/wns/g,"lmn")
but it doesnot work.
plz note that i just want to alter that specific tag with specific id rather than every wns tag..
Thank you.
You can't change the tag name of an existing DOM element; instead, you have to create a replacement and then insert it where the element was.
The basics of this are to move the child nodes into the replacement and similarly to copy the attributes. So for instance:
var wns = document.getElementById("93");
var lmn = document.createElement("lmn");
var index;
// Copy the children
while (wns.firstChild) {
lmn.appendChild(wns.firstChild); // *Moves* the child
}
// Copy the attributes
for (index = wns.attributes.length - 1; index >= 0; --index) {
lmn.attributes.setNamedItem(wns.attributes[index].cloneNode());
}
// Replace it
wns.parentNode.replaceChild(lmn, wns);
Live Example: (I used div and p rather than wns and lmn, and styled them via a stylesheet with borders so you can see the change)
document.getElementById("theSpan").addEventListener("click", function() {
alert("Span clicked");
}, false);
document.getElementById("theButton").addEventListener("click", function() {
var wns = document.getElementById("target");
var lmn = document.createElement("p");
var index;
// Copy the children
while (wns.firstChild) {
lmn.appendChild(wns.firstChild); // *Moves* the child
}
// Copy the attributes
for (index = wns.attributes.length - 1; index >= 0; --index) {
lmn.attributes.setNamedItem(wns.attributes[index].cloneNode());
}
// Insert it
wns.parentNode.replaceChild(lmn, wns);
}, false);
div {
border: 1px solid green;
}
p {
border: 1px solid blue;
}
<div id="target" foo="bar" onclick="alert('hi there')">
Content before
<span id="theSpan">span in the middle</span>
Content after
</div>
<input type="button" id="theButton" value="Click Me">
See this gist for a reusable function.
Side note: I would avoid using id values that are all digits. Although they're valid in HTML (as of HTML5), they're invalid in CSS and thus you can't style those elements, or use libraries like jQuery that use CSS selectors to interact with them.
var element = document.getElementById("93");
element.outerHTML = element.outerHTML.replace(/wns/g,"lmn");
FIDDLE
There are several problems with your code:
HTML element IDs must start with an alphabetic character.
document.getElementById("99").replace(/wns/g,"lmn") is effectively running a replace command on an element. Replace is a string method so this causes an error.
You're trying to assign this result to document.getElementById("99").innerHTML, which is the HTML inside the element (the tags, attributes and all are part of the outerHTML).
You can't change an element's tagname dynamically, since it fundamentally changes it's nature. Imagine changing a textarea to a select… There are so many attributes that are exclusive to one, illegal in the other: the system cannot work!
What you can do though, is create a new element, and give it all the properties of the old element, then replace it:
<wns id="e93" onclick="wish(id)">
...
</wns>
Using the following script:
// Grab the original element
var original = document.getElementById('e93');
// Create a replacement tag of the desired type
var replacement = document.createElement('lmn');
// Grab all of the original's attributes, and pass them to the replacement
for(var i = 0, l = original.attributes.length; i < l; ++i){
var nodeName = original.attributes.item(i).nodeName;
var nodeValue = original.attributes.item(i).nodeValue;
replacement.setAttribute(nodeName, nodeValue);
}
// Persist contents
replacement.innerHTML = original.innerHTML;
// Switch!
original.parentNode.replaceChild(replacement, original);
Demo here: http://jsfiddle.net/barney/kDjuf/
You can replace the whole tag using jQuery
var element = $('#99');
element.replaceWith($(`<lmn id="${element.attr('id')}">${element.html()}</lmn>`));
[...document.querySelectorAll('.example')].forEach(div => {
div.outerHTML =
div.outerHTML
.replace(/<div/g, '<span')
.replace(/<\/div>/g, '</span>')
})
<div class="example">Hello,</div>
<div class="example">world!</div>
You can achieve this by using JavaScript or jQuery.
We can delete the DOM Element(tag in this case) and recreate using .html or .append menthods in jQuery.
$("#div-name").html("<mytag>Content here</mytag>");
OR
$("<mytag>Content here</mytag>").appendTo("#div-name");

Categories

Resources