Javascript dynamic element creation leads to shadow content in HTML - javascript

I create a class and elements inside the class using the following function in javascript and add it to another class using appendchild function.
function createClass(menu)
{
console.log('class entered');
var newNode = document.createElement('div');
newNode.className = 'item';
var input = document.createElement('input');
input.setAttribute("type","checkbox");
input.setAttribute("id",menu);
input.innerText=menu;
var label = document.createElement('label');
label.setAttribute("for", menu);
label.innerText=menu;
input.appendChild(label);
newNode.appendChild(input);
return newNode;
}
But, the contents is not displayed in the html page. The class is added. When the body of the html is displayed in the console, the class is added to the body but before the inner text, it says "shadow content (user Agent)".
How do I make them visible?

You've create new DOM elements but never actually attached them to the current document. The missing part is to to add your new DOM element to the document:
document.body.appendChild(createClass('hello'))

Related

How to post a paragraph in HTML with CSS styling applied?

I am using the following code to print a paragraph when the button is clicked:
document.querySelector('button')
.addEventListener('click', function() {
const p = document.createElement('p');
p.id = "text";
const val = document.getElementById('forminput').value;
if (val.length) {
p.innerHTML = val;
document.querySelector('div').appendChild(p);
}
});
When the paragraph is posted, I want it to retain the same CSS styling as well as the same onclick function as the styling and function I use for other content.
What would be the right way to do it?
If you have some styling set up for your p tags already, then this would automatically apply when you render the new p tag.
Else you can create a custom css class that holds the styling you're wanting to apply, and then add this classList to your newly rendered p tag as follows:
const p = document.createElement('p');
p.classList.add('your-class');

Javascript only last event listener works

It's very difficult for me to show you my code, as it's all over the place, but what I'm trying to do is this:
I am injecting html code into the DOM in a function buy using .innerHTML, I wish to add a click event to an icon that is being injected in this step, as at this moment in time I know its id. So after I've injected it I write:
document.getElementById(product.id+"x").addEventListener("click", removeItem);
product.id is created above and this element is a 'X' button, that when clicked will be removed from the screen.
The trouble is, this code is run many times as there are many items to be displayed on the screen. And when finished, only the last even made fires when the 'X' button is pressed.
Any suggestions?
EDIT:
I am unable to use jquery in this project.
Here is my code:
function createHTML(targetID, product) {
var target = document.getElementById(targetID);
total = (parseFloat(total) + parseFloat(product.price)).toFixed(2);;
target.innerHTML += '<article class="item" id="'+product.id+'"><img class="item_img" src="../'+product.image+'" width=100 height=100><h1 class="item_name">'+product.name+'</h1><p class="item_description">'+product.desc+'</p><h1 class="item_quantity">Quantity: '+product.quantity+'</h1><h1 class="item_price">£'+product.price+'</h1><i id="'+product.id+'x" class="fa fa-times"></i></article>';
document.getElementById(product.id+"x").addEventListener("click", removeItem, true);
}
So you're adding new elements to a container by overwriting the innerHTML or appending to it using +=. This is your problem. When you overwrite the innerHTML or append to it, you are destroying and recreating all elements within it and this causes them to lose any bound event handlers (ie your click handler).
This fiddle reproduces your problem. Only the last button has a click handler.
The solution is to build DOM elements using document.createElement() and use appendChild() or similar to append them, instead of creating/appending raw HTML. This way, your previous elements event handlers will remain intact.
This Fiddle uses DOM nodes instead of raw HTML and all buttons have a click handler.
Example fix:
var container = document.getElementById("container");
var elem;
function clicky(){
alert("clicked");
}
for(var i=0; i<4; i++){
elem = document.createElement('button');
elem.id = "btn_" + i;
elem.appendChild(document.createTextNode('Click'));
elem.addEventListener("click", clicky);
container.appendChild(elem);
}
I quess you do something like that
//Place where you add elements.
var container = document.body;
you create element and add listener to that element(button):
var button = '<button id="btn1x">Button 1</button>';
container.innerHTML += button;
//product.id = 'btn1';
document.getElementById(product.id+"x").addEventListener("click", removeItem);
and then you add in the same way new elements and add for them event listeners before next element will be generated.
If my quess is right, then your problem is that you replace whole content of container so previous event listens are lost.
stringVariable += 'abc' is the same as stringVariable = stringVariable + 'abc'. Because of that you overwrite html.
You should create elements from functions, not from string as you do now.
var button = document.createElement('button');
button.id = product.id + 'x';
button.innerText = 'Button 1'; // Title of button.
//Add button to container.
container.appendChild(button);
//Add event listener to created button.
button.addEventListener('click', myFunc);
UPDATE:
There are a way to parse your string to element.
First create container where will be set inner html from string, then get from that temp container first element (or more elements, depends from your html string), then add them to container and add to these elements listeners.
DEMO: http://jsfiddle.net/3cD4G/1/
HTML:
<div id="container">
</div>
Javascript:
var container = document.getElementById("container");
function clicky(){
alert("clicked");
}
var tempContainer = document.createElement('div');
for(var i=0; i<4; i++){
//Create your element as string.
var strElem = "<button type='button' id='btn_" + i + "'>Click</button>";
//Add that string to temp container (his html will be replaced, not added).
tempContainer.innerHTML = strElem.trim();//Trim function used to prevent empty textnodes before element.
//Get element from temp container.
var button = tempContainer.children[0];
//Empty tempContainer for better security (But about which security I'm talking in JavaScript in string element generation :) )
tempContainer.innerHTML = '';
//Add your button to container.
container.appendChild(button);
//Add event listener to button:
//document.getElementById("btn_" + i).onclick = clicky;
//Better way to add event listener:
button.addEventListener('click', clicky);
}
DEMO: http://jsfiddle.net/3cD4G/1/

createNewElement and appendChild to existing content

I am trying to understand JavaScript a little better and am having trouble creating elements and appending values to them.
All I want to do is create a new paragraph element, which will contain a new string, and add the paragraph to my existing div tag using appendChild.
var oldParagraph = document.getElementById('content')
var newParagraph = document.createElement('p');
var text = document.createTextNode("i am a new text node.");
newParagraph.setAttribute('class', 'red');
function addText(){
document.oldParagraph.appendChild(newParagraph);
document.newParagraph.appendChild(text);
}
my HTML is simple:
<div id="content"></div>
Your code should be this:
function addText(){
oldParagraph.appendChild(newParagraph);
newParagraph.appendChild(text);
}
oldParagraph and newParagraph are variables containing DOM object references. You operate on those DOM references directly.
In practice, I would think you'd organize your code more like this with local variables instead of global variables:
function addText() {
var newParagraph = document.createElement('p');
newParagraph.className = 'red';
newParagraph.appendChild(document.createTextNode("i am a new text node."));
document.getElementById('content').appendChild(newParagraph);
}
Working demo: http://jsfiddle.net/jfriend00/42ffq/.

How can I append new "p" element with formatted text

I have a javascript function designed to dynamically append text to my document (and slides it down with JQuery). I create a new "p" element, and then I want to add text to it, but I need this text to have several formats. For example, I need the first part to be italicized, second part to be underlined, and third part to be white. As of now, I managed to get three different "div" elements with their own text nodes, each with their own style, but this makes it on three separate lines. I need it all on one line. Is there any way I can insert HTML tags into a text node, or somehow split the internal string up so I can style each part separately?
This code demonstrates the closest I got, but this puts each styled text node on different lines, and I need it all on one line in that p element:
function append_announcement(time_string, user_by, text){
newp = document.createElement("p");
head = document.createElement("span");
headt = document.createTextNode("You wrote: ");
head.appendChild(headt);
body = document.createElement("div");
bodyt = document.createTextNode(text);
body.appendChild(bodyt);
body.setAttribute("style", "color: white");
foot = document.createElement("div");
foott = document.createTextNode("Done.");
foot.appendChild(foott);
newp.appendChild(head);
newp.appendChild(body);
newp.appendChild(foot);
newp.setAttribute("align", "center");
newp.style.display = "none";
document.getElementById("announcement_posts").insertBefore(newp,
document.getElementById("announcement_posts").firstChild);
$("p").slideDown("slow");
}
Change the <div>s for <span>s, they're displayed inline by default.
Alternatively you could apply a class to the <div> elements you create and set that class to display: inline-block; using CSS.
Example
function append_announcement(time_string, user_by, text){
newp = document.createElement("p");
var i = document.createElement("i");
i.textContent = ("You wrote ");
var span = document.createElement("span");
span.textContent = text;
span.style.color = "white";
var u = document.createElement("u");
u.textContent = " Done.";
newp.appendChild(i);
newp.appendChild(span);
newp.appendChild(u);
newp.setAttribute("align", "center");
newp.style.display = "none";
document.getElementById("announcement_posts").insertBefore(newp,
document.getElementById("announcement_posts").firstChild);
$("p").slideDown("slow");
}
You want to create elements that display inline like <i>, <u> or <span>

dynamically adding/removing a div to html

I want to dynamically create a div element with id="xyz". Now before creating this, I want to remove any other div with id ="xyz" if it exists. How can i do it?
var msgContainer = document.createElement('div');
msgContainer.setAttribute('id', 'xyz'); //set id
msgContainer.setAttribute('class', 'content done'); // i want to add a class to it. it this correct?
var msg2 = document.createTextNode(msg);
msgContainer.appendChild(msg2);
document.body.appendChild(msgContainer);
}
How can i remove all divs with id =xyz if they exist before executing above code?
Removing:
var div = document.getElementById('xyz');
if (div) {
div.parentNode.removeChild(div);
}
Or if you don't control the document and think it may be malformed:
var div = document.getElementById('xyz');
while (div) {
div.parentNode.removeChild(div);
div = document.getElementById('xyz');
}
(Alternatives below.)
But you only need the loop with invalid HTML documents; if you control the document, there's no need, simply ensure the document is valid. id values must be unique. And yet, one sees plenty of documents where they aren't.
Adding:
var msgContainer = document.createElement('div');
msgContainer.id = 'xyz'; // No setAttribute required
msgContainer.className = 'someClass' // No setAttribute required, note it's "className" to avoid conflict with JavaScript reserved word
msgContainer.appendChild(document.createTextNode(msg));
document.body.appendChild(msgContainer);
If you don't like the code duplication in my loop above and you think you need the loop, you could do:
var div;
while (!!(div = document.getElementById('xyz'))) {
div.parentNode.removeChild(div);
}
or
var div;
while (div = document.getElementById('xyz')) {
div.parentNode.removeChild(div);
}
...although that last may well generate lint warnings from various tools, since it looks like you have = where you mean == or === (but in this case, we really do mean =).

Categories