Creating elements within elements with javascript - javascript

Noob here. I searched on the internet a bit to find an answer to a question and I can't seem to find any (and that brings my hope down). So here I am.
I was wondering if there is a way to create an HTML element with javascript, BUT inside the newly created HTML element to create also another HTML element with javascript. I guess you can call it elementception //wink
To be more specific, I would like to create a paragraph with text, but I would like to include links in that text (or possibly buttons?).
var para = document.createElement("P");
var t = document.createTextNode("This is a paragraph. Can I do this: <a href='blabla'>like so?</a>");
para.appendChild(t);
document.body.appendChild(para);
I tried writing HTML tags inside the strings of the TextNode, but even I can see that was stupid of me. Is there a noobish(simple) way to achieve this, or any way at all? If I'm asking the impossible, please be harsh and blunt about it, so that I never ask questions again.
Thanks.

The simplest way to do this would be:
para.innerHTML = 'This is a paragraph. Here is a link: like so?';

I would use the DOM API approach instead of using innerHTML for readability, maintainability and security reasons. Sure innerHTML has been around for a long time, but just because it is easy doesn't mean you should use it for everything.
As well, if you're going to be learning JavaScript you should get acquainted with the DOM API sooner than later. It will save you a lot of headaches down the road if you get the hang of the API now.
// Create the parent and cache it in a variable.
var para = document.createElement( "p" );
// Create a text node and append it to the child.
// We don't need to cache this one because we aren't accessing it again.
para.appendChild( document.createTextNode( "This is a paragraph. Can I do this: " ) );
// Create our link element and cache it in a variable.
var link = document.createElement( "a" );
// Set the link's href attribute.
link.setAttribute( 'href', 'blabla' );
// Create a text node and append it to the link
// We don't need to cache the text node.
link.appendChild( document.createTextNode( 'like so?' ));
// Append the link to the parent.
para.appendChild( link );
// Append the parent to the body.
document.body.appendChild( para );
DOM API methods used:
Document.createElement()
Document.createTextNode()
Node.appendChild()
Element.setAttribute()
Further reading:
Document Object Model (DOM)
Element.innerHTML Security Considerations
Advantages of createElement over innerHTML?

Simply use innerHTML attribute to put HTML inside your element instead of createTexteNode, here's what you need:
var para = document.createElement("P");
para.innerHTML = "This is a paragraph. Can I do this: <a \"blabla\">like so?</a>";
document.body.appendChild(para);
Because as its name says, document.createTextNode() will only create a text and can't create HTML elements.
var para = document.createElement("P");
para.innerHTML = "This is a paragraph. Can I do this: like so?";
document.body.appendChild(para);

Related

Can I create a self-closing element with createElement?

I'm trying to append a line of HTML before all the children of the body.
Right now I have this:
// Prepend vsr-toggle
var vsrToggle = document.createElement("div");
vsrToggle.innerHTML = "<input type='checkbox' name='sr-toggle' id='srToggle'><label for='srToggle' role='switch'>Screen reader</label>"
document.body.insertBefore(vsrToggle, pageContent);
It's working fine because the HTML is being added to the created div. However, I need to prepend this element without wrapping it in a div.
Is there a way to prepend the HTML without first creating an element? If not, can I create the input as a self-closing element and append the label to it?
Is there a better way to achieve this?
Cheers!
Use document.createDocumentFragment() to create a node, that isn't automatically added to the document. You can then add elements to this fragment and finally add it to the document.
This is a good link: Document fragment
How to use:
var fragment = document.createDocumentFragment();
fragment.innerHTML = '<input />';
document.body.appendChild(fragment);
I ended up using createRange and createContextualFragment to turn the string into a node that I could prepend using insertBefore.:
// Prepend vsr-toggle
var vsrToggle = document.createRange().createContextualFragment("<input
type='checkbox' name='sr-toggle' id='srToggle'><label for='srToggle'
role='switch'>Screen reader</label>");
document.body.insertBefore(vsrToggle, pageContent);
Edit: As Poul Bak showed, there is a very useful feature in the DOM API for that. Creating elements separately (instead of having them parsed as a string) allows more control over the elements added (for example you can outright attach an event listener without queryiing it from the DOM later), but for a larger amounts of elements it quickly becomes very verbose.
Create each element separately, and insert it before the body content using
document.body.insertBefore(newNode, document.body.firstChild);
const vsrToggle = document.createElement("input");
vsrToggle.name="sr-toggle";
vsrToggle.id="srToggle";
vsrToggle.type="checkbox";
const vsrToggleLabel = document.createElement("label");
vsrToggleLabel.setAttribute("for", vsrToggle.id);
vsrToggleLabel.setAttribute("role", "switch");
vsrToggleLabel.textContent = "Screen reader";
document.body.insertBefore(vsrToggle, document.body.firstChild);
document.body.insertBefore(vsrToggleLabel, document.body.firstChild);
<body>
<h1>Body headline</h1>
<p>Some random content</p>
</body>

How can I apply some style to JavaScript's "node" object

Imagine that I have a couple of statements as following:
var n1 = oDiv.firstChild;
var n2 = oDiv.lastChild.previousSibling.firstChild; //know this crazy, but for knowledge sake
How can I apply various styles like the following (which usually works only for "element" types and not "node" types):
//does not work
n1.style.borderWidth = "1px";
n1.style.borderColor = "#336699";
n2.style.borderStyle = "solid";
Also, is there any way to typecast "node" to "element" in JavaScript?
update:
The code I am trying to accomplish above is here http://jsfiddle.net/anthachetta/4mXrd/
The DOM works exactly the same way as HTML does. That makes sense since the DOM was designed to model HTML as objects. So, what do you do if you want to make the following bold:
Hello World
From your code, what you're trying to do is something like this:
style=font-weight:bold Hello World
Obviously that wouldn't work because it's not valid HTML. What you'd normally do is this:
<span style='font-weight:bold;'>Hello World</span>
So you need to do the same in the DOM:
// Assume you have a div "div" and the first child
// is the text node "Hello World"
var hello_world = div.firstChild;
// Now, you want to make Hello World bold.
// So you need to create a span:
var span = document.createElement('span');
span.style['font-weight'] = 'bold';
// Now wrap hello_world in the span:
span.appendChild(div.removeChild(hello_world));
The above is actual working DOM code that does what you want. But beware:
Standards compliant browsers also count whitespace as nodes.
IE doesn't count whitespace as nodes.
For example, if your HTML looks like this:
<div>
<span>Hi</span>
</div>
the standard says your DOM must look like this:
div +
|---- text node (whitespace)
'---- span +
'---- text node (Hi)
but IE does what most people probably expect:
div +
'---- span +
'---- text node (Hi)
This means that you can't blindly trust node.firstChild without checking to see if it's what you expect.
There are a few problems.
What is with the lastChild.previousSibling.firstChild mess? All that's doing is confusing you.
That mess of properties is returning you a text node, not an element.
lastChild gives you "a line", previousSibling gets the <i> tag, then firstChild returns "just". You are trying to apply a style to a text node, which you can't do, you need to style an element.
You are trying to apply the style to the nodeValue. That's a string. You can use parentNode to get to the <i> tag from the text node.
oDiv.lastChild.previousSibling.firstChild.parentNode.style.color = "#FF0000";
DEMO: http://jsfiddle.net/NTICompass/4mXrd/2/

Replace element contents with document fragment javascript

I'm trying to replace all contents of an element with a document fragment:
var frag = document.createDocumentFragment()
The document fragment is being created just fine. No problems there. I add elements to it just fine, no problems there either. I can append it using element.appendChild(frag). That works just fine too.
I'm trying to create a "replace" method similar to jQuery's HTML. I'm not worried about old-browser compatibility. Is there a magical function to replace all content of an element?
I have tried element.innerHTML = frag.cloneNode(true), (as per every 'replace element content' wiki I could find), that doesn't work. It gives me <div>[object DocumentFragment]</div>.
No libraries, please, not even a jQuery solution.
For clarity, I'm looking for a "magic" solution, I know how to remove all the existing elements one at a time and then append my fragment.
Have you tried replaceChild
something like this
element.parentNode.replaceChild(frag, element)
source: https://developer.mozilla.org/en-US/docs/DOM/Node.replaceChild
original jsFiddle: http://jsfiddle.net/tomprogramming/RxFZA/
EDIT: ahh, I didn't see replace contents. Well, just remove them first!
element.innerHTML = "";
element.appendChild(frag);
jsfiddle: http://jsfiddle.net/tomprogramming/RxFZA/1/
note that in the jsfiddle, I only use jquery to hook up the button, the entirety of the click handler is raw javascript.
Edit2: also suggested by pimvdb, but just append the new stuff to a detached element and replace.
var newElement = element.cloneNode();
newElement.innerHTML = "";
newElement.appendChild(frag);
element.parentNode.replaceChild(newElement, element);
http://jsfiddle.net/tomprogramming/RxFZA/3/
2017:
Try this Magic answer from ContentEditable field and Range
var range = document.createRange(); // create range selection
range.selectNodeContents($element); // select all content of the node
range.deleteContents() // maybe there is replace command but i'm not find it
range.insertNode(frag)
EDIT (cause my original answer was just plain dumb):
var rep = document.createElement("div");
rep.appendChild(frag);
element.innerHTML = rep.innerHTML;

javascript innerHTML adding instead of replacing

quick question, i know we can change the content of a
<div id="whatEverId">hello one<div> by using:
document.getElementById("whatEverId").innerHTML="hello two";
now, is there a way I can ADD stuff to the div instead of replacing it???
so i can get
<div id="whatEverId">hello one hello two<div>
(using something similar of course)
<div id="whatever">hello one</div>
<script>
document.getElementById("whatever").innerHTML += " hello two";
</script>
Notice that using element.innerHTML += 'content' would empty inputs and textareas to their default, blank state, unclick checkboxes, as well as removing any events attached to those elements (such as onclick, on hover etc.) because the whole innerHTML would be reinterpreted by the browser, which means .innerHTML is emptied and filled again from scratch with the combined content.
If you need to keep the state, you'd need to create a new element (a <span> for instance) and append it to the current element, as in:
let newElement = 'span'
newElement.innerHTML = 'new text'
document.getElementById('oldElement').appendChild(newElement)
document.getElementById("whatEverId").innerHTML = document.getElementById("whatEverId").innerHTML + "hello two" + document.getElementById("whatEverId").innerHTM ;
What jcomeau_ictx suggested is an inefficient way of editing the innerHTML.
Check Ben cherry's PPT http://www.bcherry.net/talks/js-better-faster
The correct way will be detaching the element and making changes to it and then appending it back to the parent node.
Use https://gist.github.com/cowboy/938767 Native javascript from this gist to
detach element.
If you are appending, you can just change your = to a +=
document.getElementById("whatEverId").innerHTML += 'hello two';
If prefixing
document.getElementById("whatEverId").innerHTML = 'hello two' + document.getElementById("whatEverId").innerHTML;
Although I would highly recommend using jQuery or MooTools javascript libraries/frameworks to do this sort of thing. If you're adding tags not just text nodes, then you should use the DOM createElement or one of the aforementioned libraries/frameworks.
You can do it by appending div string like this..
document.getElementById('div_id').innerHTML += 'Hello Two';

How to append text to a div element?

I’m using AJAX to append data to a <div> element, where I fill the <div> from JavaScript. How can I append new data to the <div> without losing the previous data found in it?
Try this:
var div = document.getElementById('divID');
div.innerHTML += 'Extra stuff';
Using appendChild:
var theDiv = document.getElementById("<ID_OF_THE_DIV>");
var content = document.createTextNode("<YOUR_CONTENT>");
theDiv.appendChild(content);
Using innerHTML:
This approach will remove all the listeners to the existing elements as mentioned by #BiAiB. So use caution if you are planning to use this version.
var theDiv = document.getElementById("<ID_OF_THE_DIV>");
theDiv.innerHTML += "<YOUR_CONTENT>";
Beware of innerHTML, you sort of lose something when you use it:
theDiv.innerHTML += 'content';
Is equivalent to:
theDiv.innerHTML = theDiv.innerHTML + 'content';
Which will destroy all nodes inside your div and recreate new ones. All references and listeners to elements inside it will be lost.
If you need to keep them (when you have attached a click handler, for example), you have to append the new contents with the DOM functions(appendChild,insertAfter,insertBefore):
var newNode = document.createElement('div');
newNode.innerHTML = data;
theDiv.appendChild(newNode);
If you want to do it fast and don't want to lose references and listeners use: .insertAdjacentHTML();
"It does not reparse the element it is being used on and thus it does not corrupt the existing elements inside the element. This, and avoiding the extra step of serialization make it much faster than direct innerHTML manipulation."
Supported on all mainline browsers (IE6+, FF8+,All Others and Mobile): http://caniuse.com/#feat=insertadjacenthtml
Example from https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
// <div id="one">one</div>
var d1 = document.getElementById('one');
d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');
// At this point, the new structure is:
// <div id="one">one</div><div id="two">two</div>
If you are using jQuery you can use $('#mydiv').append('html content') and it will keep the existing content.
http://api.jquery.com/append/
IE9+ (Vista+) solution, without creating new text nodes:
var div = document.getElementById("divID");
div.textContent += data + " ";
However, this didn't quite do the trick for me since I needed a new line after each message, so my DIV turned into a styled UL with this code:
var li = document.createElement("li");
var text = document.createTextNode(data);
li.appendChild(text);
ul.appendChild(li);
From https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent :
Differences from innerHTML
innerHTML returns the HTML as its name indicates. Quite often, in order to retrieve or write text within an element, people use innerHTML. textContent should be used instead. Because the text is not parsed as HTML, it's likely to have better performance. Moreover, this avoids an XSS attack vector.
Even this will work:
var div = document.getElementById('divID');
div.innerHTML += 'Text to append';
An option that I think is better than any of the ones mentioned so far is Element.insertAdjacentText().
// Example listener on a child element
// Included in this snippet to show that the listener does not get corrupted
document.querySelector('button').addEventListener('click', () => {
console.log('click');
});
// to actually insert the text:
document.querySelector('div').insertAdjacentText('beforeend', 'more text');
<div>
<button>click</button>
</div>
Advantages to this approach include:
Does not modify the existing nodes in the DOM; does not corrupt event listeners
Inserts text, not HTML (Best to only use .insertAdjacentHTML when deliberately inserting HTML - using it unnecessarily is less semantically appropriate and can increase the risk of XSS)
Flexible; the first argument to .insertAdjacentText may be beforebegin, beforeend, afterbegin, afterend, depending on where you'd like the text to be inserted
you can use jQuery. which make it very simple.
just download the jQuery file add jQuery into your HTML
or you can user online link:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
and try this:
$("#divID").append(data);
The following method is less general than others however it's great when you are sure that your last child node of the div is already a text node. In this way you won't create a new text node using appendData MDN Reference AppendData
let mydiv = document.getElementById("divId");
let lastChild = mydiv.lastChild;
if(lastChild && lastChild.nodeType === Node.TEXT_NODE ) //test if there is at least a node and the last is a text node
lastChild.appendData("YOUR TEXT CONTENT");
java script
document.getElementById("divID").html("this text will be added to div");
jquery
$("#divID").html("this text will be added to div");
Use .html() without any arguments to see that you have entered.
You can use the browser console to quickly test these functions before using them in your code.
Why not just use setAttribute ?
thisDiv.setAttribute('attrName','data you wish to append');
Then you can get this data by :
thisDiv.attrName;

Categories