Javascript: A couple of JS questions - javascript

I am learning this stuff and trying to understand it, so am using this instead of innerhtml.
My code:
<script>
function load() {
"use strict";
var t = document.createElement("table"),
tb = document.createElement("tbody"),
tr = document.createElement("tr"),
td = document.createElement("td");
var b = document.createElement("b");
b.appendChild(document.createTextNode(" name!"));
td.appendChild(document.createTextNode("Hello"));
td.appendChild(b);
t.style.width = "100%";
t.style.borderCollapse = 'collapse';
t.border=1;
// note the reverse order of adding child
tr.appendChild(td);
tb.appendChild(tr);
t.appendChild(tb);
// more code to populate table rows and cells
document.getElementById("theBlah").appendChild(t);
alert(t.innerHTML);
}
</script>
</head>
<body onload="load()">
problem is , onload() does not display the <table> tag, it displays from <tbody> instead... any idea why?
And finally, in this code:
var t = document.createElement("table"),
tb = document.createElement("tbody"),
tr = document.createElement("tr"),
td = document.createElement("td");
even though I am using the Var keyword just for t, and not for the others, why is it not complaining even though "use strict" is on? In fact if I add a "var" in front of "tb, "tr", "td" then it throws an error...
Thanks!

1) innerHTML is just that. It's inner. It doesn't contain the HTML of the element itself, but all the html that is within that element. There is a property called outerHTML too, but it's not included in Firefox. The only cross browser way to get outerHTML is to wrap the node in a new parent node and grab that nodes innerHTML. You can't just grab the current parent's innerHTML (You have to make a new parent) unless you're sure the element has no siblings, because if you do the siblings will included.
2) You are using commas to separate your variable decorations. That is the same as using semi-colons and putting var on each line.

InnerHtml is faster even though it's not in the spec. Its just the inner html like the above person said and not an element.
Using one Var and commas to separate your variable decorations is a good idea,
1. to reduce file size,
2. to declare all variables at the top. (to avoid hoisting problem)

Related

JavaScript - append() not appending a button, but text

Example:
var buttonHTML = "<button>MyButton</button>";
document.getElementById("myDiv").append(buttonHTML);
In this case, the function ends up appending the text into the div.
However, if I do the same with JQ:
$("#myDiv").append(buttonHTML);
In this case it will actually append the button.
Now, for various reasons, I have to use plain JS (not JQ).
Anyone have any ideas?
I am not sure how it worked with you and appended the element as text here, because there is no .append function in pure JS
But I agree with what #Sam Judge said in his answer,and also want to mention that you can do it using javascript without creating nodes one by one using javascript function Element.insertAdjacentHTML()
insertAdjacentHTML() parses the specified text as HTML or XML and
inserts the resulting nodes into the DOM tree at a specified position.
It does not reparse the element it is being used on and thus it does
not corrupt the existing elements inside the element. This avoiding
the extra step of serialization make it much faster than direct
innerHTML manipulation.
And there is another option to do the same using the .innerHTML but for sure you will need to save what's already inside to do the append effect.
This is because your var buttonHTML is just a string of text, if you append it as a child, it will create a DOM textNode, rather than an elementNode. What you want to do instead is something along the lines of the following :
var buttonHTML = document.createElement("button");
var buttonText = document.createTextNode("MyButton");
buttonHTML.appendChild(buttonText);
document.getElementById("myDiv").appendChild(buttonHTML)
you can try this code
function myFunction() {
var myButton= document.createElement("button");
myButton.style.width = "100px";
myButton.style.height = "30px";
myButton.style.background = "grey";
myButton.style.color = "white";
myButton.innerHTML = "MyButton";
document.getElementById("demo1").appendChild(myButton);
}
<button type="button" onclick="myFunction()">create another button</button>
<p id="demo1"></p>

JS. How to replace html element with another element/text, represented in string?

I have a problem with replacing html elements.
For example, here is a table:
<table>
<tr>
<td id="idTABLE">0</td>
<td>END</td>
</tr>
</table>
(it can be div, span, anything)
And string in JavaScript:
var str = '<td>1</td><td>2</td>';
(It can be anything, 123 text, <span>123 element</span> 456 or <tr><td>123</td> or anything)
How can I replace element idTABLE with str?
So:
<table>
<tr>
<td id="idTABLE">0</td>
<td>END</td>
</tr>
</table>
Becomes:
<table>
<tr>
<td>1</td>
<td>2</td>
<td>END</td>
</tr>
</table>
<!-- str = '<td>1</td><td>2</td>'; -->
<table>
<tr>
123 text
<td>END</td>
</tr>
</table>
<!-- str = '123 text' -->
<table>
<tr>
<td>123</td>
<td>END</td>
</tr>
</table>
<!-- str = '<td>123</td>' -->
I tried createElement, replaceChild, cloneNode, but with no result at all =(
As the Jquery replaceWith() code was too bulky, tricky and complicated, here's my own solution. =)
The best way is to use outerHTML property, but it is not crossbrowsered yet, so I did some trick, weird enough, but simple.
Here is the code
var str = 'item to replace'; //it can be anything
var Obj = document.getElementById('TargetObject'); //any element to be fully replaced
if(Obj.outerHTML) { //if outerHTML is supported
Obj.outerHTML=str; ///it's simple replacement of whole element with contents of str var
}
else { //if outerHTML is not supported, there is a weird but crossbrowsered trick
var tmpObj=document.createElement("div");
tmpObj.innerHTML='<!--THIS DATA SHOULD BE REPLACED-->';
ObjParent=Obj.parentNode; //Okey, element should be parented
ObjParent.replaceChild(tmpObj,Obj); //here we placing our temporary data instead of our target, so we can find it then and replace it into whatever we want to replace to
ObjParent.innerHTML=ObjParent.innerHTML.replace('<div><!--THIS DATA SHOULD BE REPLACED--></div>',str);
}
That's all
Because you are talking about your replacement being anything, and also replacing in the middle of an element's children, it becomes more tricky than just inserting a singular element, or directly removing and appending:
function replaceTargetWith( targetID, html ){
/// find our target
var i, tmp, elm, last, target = document.getElementById(targetID);
/// create a temporary div or tr (to support tds)
tmp = document.createElement(html.indexOf('<td')!=-1?'tr':'div'));
/// fill that div with our html, this generates our children
tmp.innerHTML = html;
/// step through the temporary div's children and insertBefore our target
i = tmp.childNodes.length;
/// the insertBefore method was more complicated than I first thought so I
/// have improved it. Have to be careful when dealing with child lists as
/// they are counted as live lists and so will update as and when you make
/// changes. This is why it is best to work backwards when moving children
/// around, and why I'm assigning the elements I'm working with to `elm`
/// and `last`
last = target;
while(i--){
target.parentNode.insertBefore((elm = tmp.childNodes[i]), last);
last = elm;
}
/// remove the target.
target.parentNode.removeChild(target);
}
example usage:
replaceTargetWith( 'idTABLE', 'I <b>can</b> be <div>anything</div>' );
demo:
http://jsfiddle.net/97H5Y/1/
By using the .innerHTML of our temporary div this will generate the TextNodes and Elements we need to insert without any hard work. But rather than insert the temporary div itself -- this would give us mark up that we don't want -- we can just scan and insert it's children.
...either that or look to using jQuery and it's replaceWith method.
jQuery('#idTABLE').replaceWith('<blink>Why this tag??</blink>');
update 2012/11/15
As a response to EL 2002's comment above:
It not always possible. For example, when createElement('div') and set its innerHTML as <td>123</td>, this div becomes <div>123</div> (js throws away inappropriate td tag)
The above problem obviously negates my solution as well - I have updated my code above accordingly (at least for the td issue). However for certain HTML this will occur no matter what you do. All user agents interpret HTML via their own parsing rules, but nearly all of them will attempt to auto-correct bad HTML. The only way to achieve exactly what you are talking about (in some of your examples) is to take the HTML out of the DOM entirely, and manipulate it as a string. This will be the only way to achieve a markup string with the following (jQuery will not get around this issue either):
<table><tr>123 text<td>END</td></tr></table>
If you then take this string an inject it into the DOM, depending on the browser you will get the following:
123 text<table><tr><td>END</td></tr></table>
<table><tr><td>END</td></tr></table>
The only question that remains is why you would want to achieve broken HTML in the first place? :)
Using jQuery you can do this:
var str = '<td>1</td><td>2</td>';
$('#__TABLE__').replaceWith(str);
http://jsfiddle.net/hZBeW/4/
Or in pure javascript:
var str = '<td>1</td><td>2</td>';
var tdElement = document.getElementById('__TABLE__');
var trElement = tdElement.parentNode;
trElement.removeChild(tdElement);
trElement.innerHTML = str + trElement.innerHTML;
http://jsfiddle.net/hZBeW/1/
You would first remove the table, then add the new replacement to the table's parent object.
Look up removeChild and appendChild
http://javascript.about.com/library/bldom09.htm
https://developer.mozilla.org/en-US/docs/DOM/Node.appendChild
Edit:
jQuery .append allows sting-html without removing tags: http://api.jquery.com/append/
Your input in this case is too ambiguous. Your code will have to know if it should just insert the text as-is or parse out some HTML tags (or otherwise wind up with bad HTML). This is unneeded complexity that you can avoid by adjusting the input you provide.
If the garbled input is unavoidable, then without some sophisticated parsing (preferably in a separate function), you could end up with some bad HTML (like you do in your second example... which is Bad, right?).
I'm guessing you want a function to insert columns into a 1-row table. In this case, your contents should be passed in as an array (without table, tr, td tags). Each array element will be one column.
HTML
<table id="__TABLE__"><tr><td></td></tr></table>
JS
using jQuery for brevity...
function insert_columns (columns)
{
var $row = $('<tr></tr>');
for (var i = 0; i < columns.length; i++)
$row.append('<td>'+columns[i]+'</td>');
$('#__TABLE__').empty(); // remove everything inside
$('#__TABLE__').append($row);
}
So then...
insert_columns(['hello', 'there', 'world']);
Result
<table id="__TABLE__"><tr><td>hello</td><td>there</td><td>world</td></tr></table>
If you need to actually replace the td you are selecting from the DOM, then you need to first go to the parentNode, then replace the contents replace the innerHTML with a new html string representing what you want. The trick is converting the first-table-cell to a string so you can then use it in a string replace method.
I added a fiddle example: http://jsfiddle.net/vzUF4/
<table><tr><td id="first-table-cell">0</td><td>END</td></tr></table>
<script>
var firstTableCell = document.getElementById('first-table-cell');
var tableRow = firstTableCell.parentNode;
// Create a separate node used to convert node into string.
var renderingNode = document.createElement('tr');
renderingNode.appendChild(firstTableCell.cloneNode(true));
// Do a simple string replace on the html
var stringVersionOfFirstTableCell = renderingNode.innerHTML;
tableRow.innerHTML = tableRow.innerHTML.replace(stringVersionOfFirstTableCell,
'<td>0</td><td>1</td>');
</script>
A lot of the complexity here is that you are mixing DOM methods with string methods.
If DOM methods work for your application, it would be much bette to use those.
You can also do this with pure DOM methods (document.createElement, removeChild, appendChild), but it takes more lines of code and your question explicitly said you wanted to use a string.
use the attribute "innerHTML"
somehow select the table:
var a = document.getElementById('table, div, whatever node, id')
a.innerHTML = your_text

How to use the DOM to set values in HTML table without using .innerHTML?

I recently posted some code on Code Review Stack Exchange
https://codereview.stackexchange.com/questions/8783/how-can-i-improve-performance-for-my-javascript-table-class
My code would populate an HTML table with values from an object in JavaScript
In the answer I received, it was suggested that I use the DOM to add rows to my table without using .innerHTML or jQuery. I would like to do this, but I don't know how.
My code looks like this:
var html = ... // code to get html
$(tbody).html(html);
How can I get the rows in the variable html into my table body without using innerHTML or jQuery.
I think the suggestion was probably that you use .innerText instead of .innerHTML when placing text string contents in an element (either pre-existing, or one you're creating on the fly). It's just safer to do. The reason being: if somehow in your retrieval of the contents you get a string that has something like "<script> //do something bad </script>" in it, that potentially dangerous script will be executed when appended to the DOM using .innerHTML. However, if you use .innerText it will just be placed in the DOM as a string, and not be evaluated as a script to run.
If you have an HTML string, your don't want to parse it yourself like Inerdial pointed it out in the comments.. Let the browser parse it for you with innerHTML/jQuery.
I will show you how to do plain DOM manipulation though:
var thediv = document.createElement('DIV');
thediv.style.backgroundColor = 'white';
thediv.appendChild(document.createTextNode('some text'));
document.getElementById('someElement').appendChild(thediv);
That's the basics, you can create tables and table rows and insert them in that fashion.
Why not use jQuery or innerHTML is another question.
EDIT: added some text to the div
Thanks
It seems that if you use the approach you're trying:
var html = '<tr><td>This is a div</td></tr>';
$(tbody).html(html);
You will be using innerHTML. To avoid this, you need to create DOM nodes instead:
var cell = document.createElement('td');
var row = document.createElement('tr');
var tbody = document.getElementsByTagName('tbody')[0];
row.appendChild(cell);
tbody.appendChild(row);
Of course this will append an empty td to a tr and append that to the tbody. To place content in the cell, you'd still have to use innerHTML:
var cell = document.createElement('td');
cell.innerHTML = "This is text inside of the created 'td' DOM node.";
var row = document.createElement('tr');
var tbody = document.getElementsByTagName('tbody')[0];
row.appendChild(cell);
tbody.appendChild(row);
JS Fiddle demo.
Using jQuery, this can be condensed to:
var cell = $('<td />').text("This is text inside of the created 'td' DOM node.");
var row = $('<tr />');
var tbody = $('tbody:first');
row.append(cell).appendTo(tbody);
JS Fiddle demo.
A link to a comparison of the approaches ('vanilla' JavaScript against jQuery), at JS Perf.

Update a tbody's html with javascript (no lib): possible?

I want to update the contents of a TBODY (not the entire TABLE, because there's much more semi-meta data (LOL) in that). I get >= 0 TR's from the server (XHR) and I want to plump those in the existing table. The fresh TR's must overwrite the existing TBODY contents.
I've made a very simple, static example on jsFiddle that works in Chrome and probably all the rest, except for IE (I only use Chrome and test in IE8).
In Chrome, the very first attempt works: plump the TR's in the TBODY. No problem!
In IE it doesn't... I've included a not working example of what I had in mind to get it working.
I'm sure this problem isn't new: how would I insert a string with TR's in an existing TBODY?
PS. jQuery doesn't have a problem with this!? It's used here on SO. jQuery does something to the HTML and then inserts it as HTML nodes..? Or something? I can't read that crazy lib. It happens in this file (look for "html: function(". That's where the magic starts.
Anybody have a function or idea for this to work without JS library?
Here is a good resource about the problems of innerHTML and IE.
The bottom line is that on tbody the innerHTML property is readonly.
Here is a solution presented in one of the comments:
var innerHTML = "<tr><td>Hello world!</td></tr>";
var div = document.createElement("DIV");
div.innerHTML = "<table>" + innerHTML + "</table>";
// Get the tr from the table in the div
var trElem = div.getElementsByTagName("TR")[0];
Regarding the jQuery part of the question:
//inside the html() function:
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
//inside the empty() function (basically removes all child nodes of the td):
while ( elem.firstChild ) {
elem.removeChild( elem.firstChild );
}
//append calls domManip applying this to all table rows:
if ( this.nodeType === 1 ) {
this.appendChild( elem );
}
//domManip as far as I can tell creates a fragment if possible and calls the three lines above with this=each row in turn, elem=the tbody(created if missing)
Using plain JavaScript, you can set the innerHTML property of the relevant element. The text that you set can contain a mix of HTML and text. It will be parsed and added to the DOM.

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