appendChild() and createElement() Javascript question - javascript

When I use appendChild() and createElement() in my code, the subsequent styles for the defined CSS IDs are not applied. Can someone tell me why? Here's my code:
function searchDone(results) {
var result = null;
var parent = document.getElementById('postWrap');
var child = null;
parent.innerHTML = '';
var insertHTML =" ";
//Paginating Results Links
resultNum = results.SearchResponse.Web.Total;
resultNum = resultNum/10;
child = document.createElement('div');
child.id = "paging";
if(results.SearchResponse.Web.Offset != 0){
insertHTML ='<span><a class="jsonp b" href="#" rev="'+(results.SearchResponse.Web.Offset-10)+'"><</a></span>';
}
if(results.SearchResponse.Web.Offset == 0){
insertHTML += '<span>1</span>';
}else{
insertHTML +='<span><a class="jsonp" href="#" rev="0">1</a></span>';
}
for(var i = 1; i <= resultNum; i++){
if((results.SearchResponse.Web.Offset/10) == i){
insertHTML += '<span>'+(i+1)+'</span>';
}else{
insertHTML += '<span><a class="jsonp b" href="#" rev="'+i*10+'">'+(i+1)+'</a></span>';
}
}
if(results.SearchResponse.Web.Total - results.SearchResponse.Web.Offset > 10){
insertHTML += '<span><a class="jsonp b" href="#" rev="'+(results.SearchResponse.Web.Offset+10)+'">></a></span>';
}
child.innerHTML = insertHTML;
parent.appendChild(child);
I then have some other code which processes my search query via API to Bing (only because Google now charges... )
Next, I use the same methods to insert another div:
//Insert Paginating results again
child = null;
child = document.createElement('div');
child.innerHTML = insertHTML;
child.id = "searchResultsPages";
parent.appendChild(child);
Now I'd like to apply some styles to these numbers. However, when I apply a style to searchResultsPage, like
#searchResultsPages{
float: right;
}
I don't get the style being passed on. The curious thing is that if I only insert one of these two elements, everything goes as planned and the style shows up fine. The problem is that I'd like pages displayed at the top and bottom of the search.
Any ideas why this is happening? I think it might have something to do with an element being used twice, but I don't know why this would effect anything if the objects are different.
Thanks.

child.id = "searchResultsPages";
#searchResultsPage{
See anything wrong there? :)
Like an s

IDs should be unique within the page so if you have two elements with id="searchResultsPage" the behaviour can get a bit screwy and the HTML is invalid. Instead, use a class="searchResultsPage" if there will be multiple elements.
The issue of the missing 's' the other commenters point out is also quite important though hopefully that was just a typo in the question.

Related

Remove HTML Element in a parent HTML Element

I have a basic table and one column should have an active/waiting badge.
I receive this information by my implemented Websocket. Works fine so far.
I was able to add at initial rendering the badge to the column that it looks like this:
<td th:id="${car.getBrand()}"><span value="${car.getBrand()}" class="badge badge-success">Active</span></td>
or this
<td th:id="${car.getBrand()}"><span value="${car.getBrand()}" class="badge badge-light">Waiting</span></td>
This was implemented by the help of this code and does what it should do:
var tableEntry = document.getElementById(message.content[0])
if (message.content[1] === 'true') {
var span = document.createElement('span')
span.value = message.content[0]
span.innerHTML = '<span class="badge badge-success">Active</span>'
tableEntry.appendChild(span)
} else {
var span = document.createElement('span')
span.value = message.content[0]
span.innerHTML = '<span class="badge badge-light">Waiting</span>*'
tableEntry.appendChild(span)
}
What is my problem?
The last hours I spent with trying to remove the existing span element inside the <td>...</td> before I insert the new span code with the function I created above. The matching entry should be found by the span attribute value. I really tried hard but I am giving up now.
Please help me.
Depending on what exactly you want to do, you need to either edit the exact node you want directly, or remove the old node and append a new node. Without more context, I'll suggest replacing the node outright:
var tableEntry = document.getElementById(message.content[0])
// Note that we can move the duplicated code to outside if block
// and make it clearer as to exactly the difference between the
// branches
var span = document.createElement('span')
span.value = message.content[0];
if (message.content[1] === 'true') {
span.innerText = 'Active';
span.className = 'badge badge-success';
} else {
span.innerText = 'Waiting';
span.className = 'badge badge-light';
}
// Here we remove all children
while (tableEntry.firstChild)
tableEntry.removeChild(tableEntry.firstChild);
// ... before add the new content
tableEntry.appendChild(span);
Edit
If you would rather do this with jQuery, try:
var $newSpan = $('<span>', {'class': 'badge'});
var $td = $('#' + message.content[0]);
if (message.content[1] === 'true')
$newSpan.addClass('badge-success').text('Active');
else
$newSpan.addClass('badge-light').text('Waiting');
$td.empty().append( $newSpan );
Alternatively, you could update the span that's there directly:
if ( message.content[1] === 'true' )
$('#' + message.content[0]).find('span').removeClass('badge-light').addClass('badge-success').text('Active');
else
$('#' + message.content[0]).find('span').removeClass('badge-success').addClass('badge-light').text('Waiting');
Are you just looking for this:
$('td').find('span').remove();
Maybe i am missing something here though, and if so i can better write up a answer. Since i am not sure what is within "message.content[n]", why dont you when building the span, also add a unique ID to it. That way when you go to update the span in your javascript, you can reference the correct one to remove, then append?
//remove it
$('td').find('#yourSpanId').remove()
//now assign id to new span object
span.id = message.propetyToUseAsId //i do not know all properties of your object
var span = document.createElement('span')
span.value = message.content[0]
span.innerHTML = '<span class="badge badge-light">Waiting</span>*'
/*********** soemthing like this *************/
span.id = message.propetyToUseAsId //i do not know all properties of your object
tableEntry.appendChild(span)
Does this help? Would be easier if we could see all object properties, and look for object ID or something unique to each object you could use as the id. I like to use custom attributes instead of ID's when building template like this, so i can reference anything based on each object later in page cycle or life quickly.
Since I was asked by an admin to post the solution here, I do it.
This is the code that does the job
var message = JSON.parse(payload.body)
var tableEntry = document.getElementById(message.content[0])
tableEntry.removeChild(tableEntry.firstChild)
if (message.content[1] === 'true') {
tableEntry.innerHTML = '<span class="badge badge-success">Active</span>'
} else {
tableEntry.innerHTML = '<span class="badge badge-light">Waiting</span>'
}
Thank you for your help, I wouldn't make it without you :)

Javascript string.slice() with negative values

I am trying to hide or show divs based on the title of the page. This is only required because I can't figure out a better way of passing a value into the page.
Here's the current code in the HTML file:
function toggle(divId) {
var divArray = document.getElementsByTagName("div");
for(i = 0; i < divArray.length; i++){
if(divArray[i].id == divId){
if(divArray[i].style.display != 'none'){
divArray[i].style.display = 'none';
}else{
divArray[i].style.display = '';
}
}
}
}
function togglePayLink() {
var h1Array = document.getElementsByTagName("h1");
for(i = 0; i < h1Array.length; i++){
if(h1Array[i].id == 'Title'){
var title = h1Array[i].innerHTML;
title = title.slice(1);
title = title.slice(-4);
toggle('descr'+ title);
}
}
}
Also in the HTML file is a header with the page title. The %%GLOBAL_PageTitle%% is replaced in server side code that I don't have access to. However, the values will be "$100 Fee" (with different numbers).
<h1 id="Title" class="TitleHeading">%%GLOBAL_PageTitle%%</h1>
Finally, I have a set of hidden divs with id's in the format descr + a number, so if the page title is "$100 Fee" I want to show the div with the id "descr100".
<div id="descr100" style="display:none;width: 75%;"></div>
When the script above runs, I get no error (I'm using chrome's console), but the div does not show. I know the toggle function works because it was previously being used with only a single div on the page that had to be toggled. I wrote the togglePayLink function, which I assume is the issue, but I have no idea how to debug this. I was wondering if the dollar sign in the title could be causing issues, but I would think I would get an error if that were the case.
EDIT: Changed the togglePayLink function to use var instead of string, but I'm getting a typeError when slice() is called.
Going forward, you should probably just assign a unique class to the page using %%GLOBAL_PageTitle%%. This way you can show/hide elements using CSS.
<div class="page %%GLOBAL_PageTitle%%">
For pages that BigCommerce doesn't give access to the HTML of the h1 for each individual page (ex. Web Pages, Account, Cart), I usually run this script on page load to strip the page title of spaces and other characters, and assign a specific class to the page element.
var catName = $('.TitleHeading').text();
var catName = catName.replace(/ /g, '');
var catName = catName.replace(/'/g, '');
var catName = catName.replace(/&/g, '');
var catName = $.trim(catName);
$('.page').addClass(''+catName+'');
The way your doing it seems a bit over the top, but if it was setup this way by someone else, I understand.
The problem is here:
String title = h1Array[i].innerHTML;
In Javascript, all variables are set with var (except for functions, which can be set other ways). So it would be:
var title = h1Array[i].innerHTML;
Additionally, you probably have to define it outside the for loop, in which case you would omit the "var" when you are setting it in the for loop:
<script language="javascript">
var title;
function togglePayLink() {
var h1Array = document.getElementsByTagName("h1");
for(i = 0; i < h1Array.length; i++){
if(h1Array[i].id == 'Title'){
title = h1Array[i].innerHTML;
title = title.slice(1);
title = title.slice(-4);
toggle('descr'+ title);
}
}
}
</script>
Edit: If you only use it in the for loop, but use it in different iterations, then I'm not sure if it can be defined locally. I'd still define it globally, though.
title.slice(-4) was giving me the last four digits of the string instead of everything before the last four digits like I thought it would. toggling the non-existent 'descrFee' div was not doing anything.

Code efficiency experts - manipulate list - string compare - append element to another div

I've got a large list with ex:
***orginal list***
<div class="ms-contactcardtext3" id="ProfileViewer_ProfileDetails">
<div cellpadding="0" cellspacing="0" class="ms-my-profileDetails">
<div>office: Oslo</div>
<br><div>User type : Ansatt i XXX</div>
<br><div>Company : XXX</div>
<br><div>phone: +47 444444
</div>
</div>
I want to manipulate and move it into a destination div on the same page
***List I want***
<div class="destination">
<div class="company">Company : XXX</div>
<div class="userType">User type : Ansatt i XXX</div>
<div class="phone">phone: +47 444444</div>
<div class="office">office: Oslo</div>
</div>
PS - read this
I can't add class / id on the large list so I have to use string compare
List may change from time to time so the order of each element can CHANGE, but I know the order
Fiddler example HERE <-- EXAMPLE CODE
If you're adding a lot of elements to the DOM, then you may want to look into using:
createDocumentFragment()
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). Consequently, using document
fragments often results in better performance.
DocumentFragment are supported in all browsers, even Internet Explorer
6, so there is no reason to not use them.
Reflow is the process by which the geometry of the layout engine's
formatting objects are computed.
Since you are adding elements, it would be best to add these elements to the document fragment and later append those elements to the DOM.
I'm not entirely sure what you're after. My attempt at efficiency relies on cloneNode to create new elements and vanilla javascript instead of jQuery. It's also more verbose than it needs to be because I have not adopted a generic loop. The regex might not be the best option. You should really compile any solutions and test them with jsperf. I have a assumed that I can't just re-use the nodes in the source container.
I should note the use of getElementsByClassName which I'd rather avoid, but for simplicity I have favoured it over manual DOM traversing and using getElementById
http://jsfiddle.net/qpZ9K/
var s = document.getElementsByClassName('ms-my-profileDetails')[0],
d = document.getElementsByClassName('destination')[0],
c = s.childNodes,
t = d.hasOwnProperty('textContent') ? 'textContent' : 'innerText',
rCompany = /^\s*Company/,
rType = /^\s*User type/,
rPhone = /^\s*phone/,
rOffice = /^\s*office/,
div = document.createElement('div'),
newDiv,
company, type, phone, office, node, text, content, link, child, i, j;
for (i = 0; i < c.length; i += 1) {
node = c[i],
text = node[t],
content = node.childNodes,
link = null;
for (j = 0; j < content.length; j += 1) {
child = content[j];
if (child.tagName === 'A') {
link = child;
break;
}
}
if(rCompany.test(text)) {
company = link;
} else if (rType.test(text)) {
type = link;
} else if (rPhone.test(text)) {
phone = link;
} else if (rOffice.test(text)) {
office = link;
}
}
newDiv = div.cloneNode(false);
newDiv.className = "company";
newDiv[t] = 'Company : ';
company && newDiv.appendChild(company.cloneNode(true));
d.appendChild(newDiv);
newDiv = div.cloneNode(false);
newDiv.className = "userType";
newDiv[t] = 'User type : ';
type && newDiv.appendChild(type.cloneNode(true));
d.appendChild(newDiv);
newDiv = div.cloneNode(false);
newDiv.className = "phone";
newDiv[t] = 'Phone : ';
phone && newDiv.appendChild(phone.cloneNode(true));
d.appendChild(newDiv);
newDiv = div.cloneNode(false);
newDiv.className = "office";
newDiv[t] = 'office : ';
office && newDiv.appendChild(office.cloneNode(true));
d.appendChild(newDiv);​
here something for you, but frankly don't understand what you really want.
var ordered = [];
$('#ProfileViewer_ProfileDetails .ms-my-profileDetails div').each(function() {
var that = $(this);
var compare = that.text().split(':')[0];
if (compare === "office") {
ordered[3] = that;
}
if (compare === "User type ") {
ordered[1] = that;
}
if (compare === "Company ") {
ordered[0] = that;
}
if (compare === "phone") {
ordered[2] = that;
}
});
$(".destination").append(ordered);

how to get value of h2 tag for a div inside other div with id using javascript

I have a div with id, which has some other div's without id.
Some thing like:
<div class="mainDivClass" id="mainDiv">
<div class="subDivClass">
<h2>one</h2>
Hello One!!
</div>
<div class="subDivClass">
<h2>two</h2>
Hello Two!!
</div>
<div class="subDivClass">
<h2>three</h2>
Hello Three!!
</div>
</div>
In my javascript, I am looping through above div like:
var divLists = document.getElementById('mainDiv').firstChild.childNodes;
for (var i = 0; i < tabLists.length; i++) {
var anchor = divLists[i].firstChild;
var iconFile;
if(i==0)
{
iconFile = 'details.png';
}
else
{
iconFile = 'search1.png';
}
anchor.style.backgroundImage = 'url(' + iconFile + ')';
anchor.style.backgroundRepeat = 'no-repeat';
anchor.style.backgroundPosition = '1px 2px';
anchor.className = 'toplevel-tab';
}
As shown, I am setting iconFile variable on value of i. So for i = 0, it would be details.png while for all others, it would be search1.png.
Now, I want to decide the iconFile variable value based on the h2 value of the element.
That is, if h2 is banana, banana.png will go in iconFile but if h2 is orange, orange.png will be selected.
How to get h2 value inside javascript ?
Thanks for reading!!
Nik
Don't use innerHTML, it's an unreliable proprietary Microsoft method; should you get used to using it you will immediately begin having problems if you start coding at an application level and not be able to figure out why. Stick to using DOM specifications instead.
An example that you can obviously throw in to a loop...
document.getElementById('subDivClass').getElementsByTagName('h2').firstChild.nodeValue
.parentNode - The parent element of the currently referenced element.
.parentNode.parentNode.parentNode - You can use this as much as you want to go up or around the DOM.
.childNodes[0] - Index of child elements, does NOT contain reference to text nodes AFTER an element (use treewalker for that).
.nodeValue - The text value of a node, do NOT use innerHTML.
.textContent - Gets or sets the text of an element (but no child elements); a bit easier than nodeValue though it still has reasonable limitations.
.previousSibling - The element BEFORE the reference element, not a child/parent.
.nextSibling - The element AFTER the reference element, not a child/parent.
You can reveal all objects (e.g. methods, properties and other objects) for any object using the in operator to discover what else is available to you...
for (i in document.getElementById('mainDiv')) {alert('i = '+i);}
It should be noted that if you're stuck using the HTML parser .nodeName will be all uppercase (e.g. the old Internet Explorer way) versus using the XML parser (application/xhtml+xml) the .nodeName will properly return the element's name as lowercase (unless you're really in to the 90's style or something).
It should also be noted that when you use previousSibling and nextSibling that line breaks alone will create a textNode and those line breaks will mess with CSS (setting the font-size to 5px will generally eliminate this).
If you want all the H2 elements inside the mainDivClass you can use the getElementsByTagName method:
var outerDiv = document.getElementById("mainDiv");
var h2s = outerDiv.getElementsByTagName("h2");
This returns all the H2 elements as an array of elements.
var answer = function () {
var parent = document.getElementById("mainDiv"),
h2 = parent.getElementsByTagName("h2"),
a = h2.length,
b;
for (b = 0; b < a; b += 1) {
switch (h2[b].innerHTML) {
case "one":
//do something
break;
case "two":
//do something
break;
default:
//do something else
break;
}
}
};
The h2 value will be used as below:
for (var i = 0; i < tabLists.length; i++) {
var anchor = tabLists[i].firstChild;
var iconFile;
if(tabLists[i].firstChild.innerHTML == "Tab 0")
{
iconFile = 'one.png';
}
else if(tabLists[i].firstChild.innerHTML == "apple")
{
iconFile = 'apple.png';
}
else if(tabLists[i].firstChild.innerHTML == "orange")
{
iconFile = 'banana.png';
}
else if(tabLists[i].firstChild.innerHTML == "banana")
{
iconFile = 'orange.png';
}
anchor.style.backgroundImage = 'url(' + iconFile + ')';
anchor.style.backgroundRepeat = 'no-repeat';
anchor.style.backgroundPosition = '1px 2px';
anchor.className = 'toplevel-tab';
}

How can I implement prepend and append with regular JavaScript?

How can I implement prepend and append with regular JavaScript without using jQuery?
Here's a snippet to get you going:
theParent = document.getElementById("theParent");
theKid = document.createElement("div");
theKid.innerHTML = 'Are we there yet?';
// append theKid to the end of theParent
theParent.appendChild(theKid);
// prepend theKid to the beginning of theParent
theParent.insertBefore(theKid, theParent.firstChild);
theParent.firstChild will give us a reference to the first element within theParent and put theKid before it.
Perhaps you're asking about the DOM methods appendChild and insertBefore.
parentNode.insertBefore(newChild, refChild)
Inserts the node newChild as a child of parentNode before the
existing child node refChild. (Returns newChild.)
If refChild is null, newChild is added at the end of the list of
children. Equivalently, and more readably, use
parentNode.appendChild(newChild).
You didn't give us much to go on here, but I think you're just asking how to add content to the beginning or end of an element?
If so here's how you can do it pretty easily:
//get the target div you want to append/prepend to
var someDiv = document.getElementById("targetDiv");
//append text
someDiv.innerHTML += "Add this text to the end";
//prepend text
someDiv.innerHTML = "Add this text to the beginning" + someDiv.innerHTML;
Pretty easy.
If you want to insert a raw HTML string no matter how complex, you can use:
insertAdjacentHTML, with appropriate first argument:
'beforebegin'
Before the element itself.
'afterbegin'
Just inside the element, before its first child.
'beforeend'
Just inside the element, after its last child.
'afterend'
After the element itself.
Hint: you can always call Element.outerHTML to get the HTML string representing the element to be inserted.
An example of usage:
document.getElementById("foo").insertAdjacentHTML("beforeBegin",
"<div><h1>I</h1><h2>was</h2><h3>inserted</h3></div>");
DEMO
Caution: insertAdjacentHTML does not preserve listeners that where attached with .addEventLisntener.
I added this on my project and it seems to work:
HTMLElement.prototype.prependHtml = function (element) {
const div = document.createElement('div');
div.innerHTML = element;
this.insertBefore(div, this.firstChild);
};
HTMLElement.prototype.appendHtml = function (element) {
const div = document.createElement('div');
div.innerHTML = element;
while (div.children.length > 0) {
this.appendChild(div.children[0]);
}
};
Example:
document.body.prependHtml(`Hello World`);
document.body.appendHtml(`Hello World`);
Here's an example of using prepend to add a paragraph to the document.
var element = document.createElement("p");
var text = document.createTextNode("Example text");
element.appendChild(text);
document.body.prepend(element);
result:
<p>Example text</p>
In order to simplify your life you can extend the HTMLElement object. It might not work for older browsers, but definitely makes your life easier:
HTMLElement = typeof(HTMLElement) != 'undefined' ? HTMLElement : Element;
HTMLElement.prototype.prepend = function(element) {
if (this.firstChild) {
return this.insertBefore(element, this.firstChild);
} else {
return this.appendChild(element);
}
};
So next time you can do this:
document.getElementById('container').prepend(document.getElementById('block'));
// or
var element = document.getElementById('anotherElement');
document.body.prepend(div);
In 2017 I know for Edge 15 and IE 12, the prepend method isn't included as a property for Div elements, but if anyone needs a quick reference to polyfill a function I made this:
HTMLDivElement.prototype.prepend = (node, ele)=>{
try { node.insertBefore(ele ,node.children[0]);}
catch (e){ throw new Error(e.toString()) } }
Simple arrow function that's compatible with most modern browsers.
var insertedElement = parentElement.insertBefore(newElement, referenceElement);
If referenceElement is null, or undefined, newElement is inserted at the end of the list of child nodes.
insertedElement The node being inserted, that is newElement
parentElement The parent of the newly inserted node.
newElement The node to insert.
referenceElement The node before which newElement is inserted.
Examples can be found here: Node.insertBefore
You can also use unshift() to prepend to a list
document.write() is not a good practice, some browsers like Chrome give you a warning if you use it, and it may be a bad solution if you are providing it to a customer, they don't want to use your code and see warnings in the debug console!
Also jQuery may also be a bad thing if you are giving your code to a customer who already uses jQuery for other functionality on their site, there will be a conflict if there is already a different version of jQuery running.
If you want to insert content into an iframe, and do that with pure JS, and with no JQuery, and without document.write(), I have a solution.
You can use the following steps
1.Select your iframe:
var iframe = document.getElementById("adblock_iframe");
2.Create an element that you want to insert into the frame, let's say an image:
var img = document.createElement('img');
img.src = "https://server-name.com/upload/adblock" + id + ".jpg";
img.style.paddingLeft = "450px";
//scale down the image is we have a high resolution screen on the client side
if (retina_test_media == true && high_res_test == true) {
img.style.width = "200px";
img.style.height = "50px";
} else {
img.style.width = "400px";
img.style.height = "100px";
}
img.id = "image";
3.Insert the image element into the iframe:
iframe.contentWindow.document.body.appendChild(img);
This is not best way to do it but if anyone wants to insert an element before everything, here is a way.
var newElement = document.createElement("div");
var element = document.getElementById("targetelement");
element.innerHTML = '<div style="display:none !important;"></div>' + element.innerHTML;
var referanceElement = element.children[0];
element.insertBefore(newElement,referanceElement);
element.removeChild(referanceElement);

Categories

Resources