Native Javascript doesn't append element on the DOM - javascript

I have a website built in Expression Engine. In the back-end there is a code snippet that takes care of a JavaScript request and build a page based on the request.
I have a HTML Page without head tag.
This page is without styling
Sample:
<div class="top-arrow"><p><!--- Rest of code --></p>
</div>
<!-- Html page continues-->
I have added the following code in my attempt and it doesnt seem to work.
var span = document.createElement("span"); //Test element
span.textContent = "A <span> element.";
var node = document.getElementsByClassName("top-arrow");
node.insertBefore(span);
Below is what I get:
TypeError: node.insertBefore is not a function
node.insertBefore(span);
How best can I append text before the div with plain JavaScript.

getElementsByClassName will return array-like node-list which does not have method insertBefore
The Node.insertBefore(newNode, referenceNode) method inserts the specified node before the reference node as a child of the current node(If referenceNode is null, the newNode is inserted at the end of the list of child nodes)
Note: referenceNode is not an optional argument, if there is no ant ref node, pass null
Try this:
var span = document.createElement("span");
span.textContent = "A <span> element.";
var node = document.getElementsByClassName("top-arrow")[0];
//_____________________________________________________^^(Get the first element from collection)
node.insertBefore(span, null);
<div class="top-arrow">
<p>
</p>
</div>

document.getElementsByClassName("top-arrow") will return a live HTMLCollection. You can use it like an array:
node = document.getElementsByClassName("top-arrow")[0];
Also, if you want the new node to appear before top-arrow you need to do:
node.parentNode.insertBefore(span, node);
As it is node has no children, so there is no need to do insertBefore.
Even though your HTML code has no body and head, the browser will 'fix' your HTML and add one.
I would write your code like this:
var span = document.createElement("span"); //Test element
span.appendChild(document.createTextNode("A <span> element."));
var node = document.getElementsByClassName("top-arrow")[0];
node.parentNode.insertBefore(span, node);

Function getElementsByClassName() returns an array containing nodes with class specified. If you want to insertBefore or append anything to it you need to specify index of an element in this array. Also, insertBefore requires two arguments in function call (elementToInsert, elemenBeforeWhichYouWantToInsert). So, something like this should work:
document.getElementsByClassName('top-arrow')[0].insertBefore(element, beforeWhatToInsert);

Thank you guys for all your input they are very informative. I have solved this without the need of manipulating my DOM element by simply copying the dynamic part of the page and actually creating a new template in the back-end of Expression Engine and my problem was solved.

Related

Inserting div into existing div with class only

I'm trying to create a new div in Javascript with two spans in it, each containing a string of text. They are then meant to be inserted before div.two in div.inner.
The div I'm trying to insert it into only has a class and I cannot target it by any ID, unfortunately.
I have also created a codepen here: https://codepen.io/lisaschumann/pen/BXqJKY
Any help is massively appreciated!
HTML
<html>
<div class="inner">
<div class="one"></div>
<div class="two"></div>
</div>
</html>
JS
window.onload=function(){
var infobox = document.createElement("div");
infobox.classList.add('infobox');
var spanOne = document.createElement("div");
var spanOneText = document.createTextNode('Important text 1');
var spanTwo = document.createElement("div");
var spanTwoText = document.createTextNode('Important text 2');
spanOne.appendChild(spanOneText);
spanTwo.appendChild(spanTwoText);
infobox.appendChild(spanOne);
infobox.appendChild(spanTwo);
var targetDiv = document.getElementsByClassName("inner");
targetDiv.insertBefore(infobox, targetDiv.childNodes[1]);
}
Errors:
Cannot read property '1' of undefined
at window.onload
The main issue is that getElementsByClassName returns a live collection of nodes rather than one node and so you would need to access the correct node in that list similar to an array: targetDiv[0], perhaps.
The easier method is to use querySelector to grab the element you want using its class, for example:
var parent = document.querySelector(".inner");
var two = document.querySelector(".two");
parent.insertBefore(infobox, two);
But! there's even a shortcut method you can use here that allows you to add an HTML string direct to the DOM which might save you a bit of time, and some code.
// Create the HTML
const html = `
<div>
<span>Text alpha</span>
<span>Text beta</span>
</div>`;
// Grab the element containing your "two" class
const two = document.querySelector('.inner .two');
// Using insertAdjacentHTML to add the HTML before the two element
two.insertAdjacentHTML('beforebegin', html);
<div class="inner">Inner
<div class="one">one</div>
<div class="two">two</div>
</div>
insertAdjacentHTML
This doesn't work because of these lines
var targetDiv = document.getElementsByClassName("inner");
targetDiv.insertBefore(infobox, targetDiv.childNodes[1]);
document.getElementsByClassName returns a NodeList. targetDiv.childNodes is undefined, because childNodes doesn't exist on a NodeList.
You need to either use a list operation like Array.prototype.forEach, change getElementsByClassName to getElementByClassName (note the s) or access the first node in the node list using the array indexer syntax.
I assume you meant to do something like this:
var targetDiv = document.getElementByClassName('inner')
targetDiv.insertBefore(infobox, targetDiv.childNodes[1])
This will insert a node in between the first and second child of the first DOM node with the class inner.
Try this out , targetDiv is an array by default due to the getElementsByClassName method , even though it has a single element.Hence you need to specify the index i.e. 0 ( as it's the first element of the array)
var targetDiv = document.getElementsByClassName("inner")[0]; targetDiv.insertBefore(infobox, targetDiv.children[1]); }
Using JQuery
$(document).ready(function(){
$(`<div>Important text 1<span></span>Important text 2<span></span></div>`).insertBefore( ".inner .two" );
)
I would encourage you to use JQuery and then shift to vanilla javascript later on. You can do simple tasks like this in just few lines of code and it is also easily debuggable because of that

javascript elements/tags array DOM node access

what's the different between using:
// assuming using elements/tags 'span' creates an array and want to access its first node
1) var arrayAccess = document.getElementsByTagName('elementName')[0]; // also tried property items()
vs
// assuming I assign an id value to the first span element/tag
// specifically calling a node by using it's id value
2) var idAccess = document.getElementById('idValue');
then if I want to change the text node....when using example 1) it will not work, for example:
arrayAccess.firstChild.nodeValue = 'some text';
or
arrayAccess.innerText/innerHTML/textContent = 'some text';
If I "access" the node through its id value then it seems to work fine....
Why is it that when using array it does not work? I'm new to javascript and the book I'm reading does not provide an answer.
Both are working,
In your first case you need to pass the tag name instead of the element name. Then only it will work.
There might be a case that you trying to set input/form elements using innerHTML. At that moment you need to use .value instead of innerHTML.
InnerHTML should be used for div, span, td and similar elements.
So your html markup example:
<div class="test">test</div>
<div class="test">test1</div>
<span id="test">test2</span>
<button id="abc" onclick="renderEle();">Change Text</button>
Your JS code:
function renderEle() {
var arrayAccess = document.getElementsByTagName('div')[0];
arrayAccess.innerHTML = "changed Text";
var idEle = document.getElementById('test');
idEle.innerHTML = "changed this one as well";
}
Working Fiddle
When you use document.getElementsByTagName('p'), the browser traverses the rendered DOM tree and returns a node list (array) of all elements that have the matching tag.
When you use document.getElementById('something'), the browser traverses the rendered DOM tree and returns a single node matching the ID if it exists (since html ID's are unique).
There are many differences when to use which, but one main factor will be speed (getElementById is much faster since you're only searching for 1 item).
To address your other question, you already have specified that you want the first element in the returned nodeList (index [0]) in your function call:
var arrayAccess = document.getElementsByTagName('elementName')[0];
Therefore, arrayAccess is already set to the first element in the returned query. You should be able to access the text by the following. The same code should work if you used document.getElementById to get the DOM element:
console.log(arrayAccess.textContent);
Here's a fiddle with an example:
http://jsfiddle.net/qoe30w2w/
Hope this helps!

How to write to a <div> element using JavaScript?

I've searched around using Google and Stack Overflow, but I haven't seemed to find a answer to this. I want to write text inside a <div> element, using JavaScript, and later clear the <div> element, and write more text into it. I am making a simple text adventure game.
This is what I am trying to do:
<DOCTYPE!HTML>
<body>
<div class="gamebox">
<!-- I want to write in this div element -->
</div>
</body>
As a new user to JavaScript, how would I be able to write inside the div element gamebox? Unfortunately, my JavaScript skills are not very good, and it would be nice if you can patiently explain what happens in the code.
You can use querySelector to get a reference to the first element matching any CSS selector. In your case, a class selector:
var div = document.querySelector(".gamebox");
querySelector works on all modern browsers, including IE8. It returns null if it didn't find any matching element. You can also get a list of all matching elements using querySelectorAll:
var list = document.querySelectorAll(".gamebox");
Then you access the elements in that list using 0-based indexes (list[0], list[1], etc.); the length of the list is available from list.length.
Then you can either assign HTML strings to innerHTML:
div.innerHTML = "This is the text, <strong>markup</strong> works too.";
...or you can use createElement or createTextNode and appendChild / insertBefore:
var child = document.createTextNode("I'm text for the div");
div.appendChild(span); // Put the text node in the div
Those functions are found in the DOM. A lot of them are now covered in the HTML5 specification as well (particularly Section 3).
Select a single element with document.querySelector or a collection with document.querySelectorAll.
And then it depends, on what you want to do:
Writing Text into the div or create an Element and append it to the div.
Like mentioned getElementsByClassName is faster. Important to know it when you use this you get returned an array with elements to reach the elment you want you specify its index line [0], [1]
var gameBox = document.getElementsByClassName('gamebox')[0];
Here how you can do it
//returns array with elements
var gameBox = document.getElementsByClassName('gamebox');
//inner HTML (overwrites fsd) this can be used if you direcly want to write in the div
gameBox[0].innerHTML ='<p>the new test</p>';
//Appending when you want to add extra content
//create new element <p>
var newP = document.createElement('p');
//create a new TextNode
var newText = document.createTextNode("i'm a new text");
//append textNode to the new element
newP.appendChild(newText);
//append to the DOM
gameBox[0].appendChild(newP);
https://developer.mozilla.org/en-US/docs/Web/API/document.createElement
https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByClassName

How to "create" HTML elements via Javascript?

Perhaps there's a better way to word my question by saying "Dynamically create DOM elements via Javascript", but I decided to write the simple title in case the latter was wrong. Anyway, is there a way I can "spawn" HTML elements via Javascript? For example, I can click a button on my site, and a paragraph will appear?
You can use createElement() like this:
var el = docment.createElement("elementtype");
This will create any element, if you replace elementtype with the type of element ("div", "p", etc.)
After that, you can use the native .appendChild() or .insertBefore() methods on whichever element you want to attach this new created element onto.
var attachTo = document.getElementById('appendToMe');
attachTo.appendChild(el);
And it'll be on the page after the last element inside of that element.
References:
https://developer.mozilla.org/en-US/docs/Web/API/document.createElement
https://developer.mozilla.org/en-US/docs/Web/API/Node.appendChild
https://developer.mozilla.org/en-US/docs/Web/API/Node.insertBefore
var element = document.createElement('p');
element.innerHTML = "Hey, this is a new paragraph!";
parentElement.appendChild(element);
For more information, refer to document.createElement and Node.appendChild

Surrounding individual words inside HTML text with SPAN tags?

I need to surround individual words inside an HTML element with SPAN tags. So something like this:
Foo <span class="f1 b0">bar <b>baz</b> boo blah</span> lorem ipsum
Should become this:
<span>Foo</span> <span class="f1 b0"><span>bar</span> <b><span>baz</span></b>
<span>blah</span></span> <span>lorem</span> <span>ipsum</span>
The reason is that I want to be able to figure out what word, specifically is under the cursor using "document.elementFromPoint(X, Y)". I tried using a simple regex:
theElement.innerHTML.replace(/\b(\w+)\b/g, "<span>$1</span>")
...but that won't work since the HTML element in question will most definitely have elements inside of it. I would just use that regex on the innerText instead of innerHTML but then I'd lose all existing formatting.
I have tried walking the children of the element, performing that regex replacement on each but sometimes the child elements have their own HTML tags within and I can't figure out how to perform a replacement of the text that comes before or after tags.
Anyone have a good solution?
To do this you will need to walk the DOM and understand how to process the individual nodes.
The basic walk code is this:
function walk(root)
{
if (root.nodeType == 3) // text node
{
doReplace(root);
return;
}
var children = root.childNodes;
for (var i = children.length - 1 ; i >= 0 ; i--)
{
walk(children[i]);
}
}
The walk function checks all the children of the input node and:
if it sees a text node it calls the replacement function
otherwise it recursively calls itself with the child node as the new input node.
Note that because the code in-place replaces nodes, the "children" node list will be affected by the replacement. To avoid this affecting the algorithm, the children are visited in reverse order.
The doReplace function is like this:
function doReplace(text)
{
var div = document.createElement("div");
div.innerHTML = text.nodeValue.replace(/\b(\w+)\b/g, "<span>$1</span>");
var parent = text.parentNode;
var children = div.childNodes;
for (var i = children.length - 1 ; i >= 0 ; i--)
{
parent.insertBefore(children[i], text.nextSibling);
}
parent.removeChild(text);
}
This creates a container node, then applies the regex and uses innerHTML to parse the result into a DOM fragment. The children of the div element can then replace the text node in the document. Again the moving of the nodes is done in reverse order so that the mutation of the source node list doesn't affect the loop.
Finally, the change can be applied by calling the walk function.
e.g.
window.onload = function() { walk(document.body); };
A complete working example can be found at http://www.alohci.net/text/html/wordwrapper.htm.ashx
You can inspect the source of this jQuery plugin to see how they do this, then extract the functionality you need.
try using .wrap() jQuery method

Categories

Resources