When appending elements to a page with jQuery, seems I have basically 3 options, summarized here:
function tripleAppend() {
//1 - append using jQuery, like so:
var withjquery = $("<p></p>").text("Appending with jquery")
//2 - Using the html directly formatted:
var withhtml = "<p>Appending html</p>"
//3 - Create & append a DOM element:
var withDOM = document.createElement("p");
withDOM.innerHTML = "Appending a DOM element"
//or withDOM.textContent = (....)
$("body").append(withjquery, withhtml, withDOM)
}
Are there important differences between those 3 approaches - any one that is more portable or more limited for a more advanced append? If I'm going to pick one these as my "go-to" solution, any reason to lean for one or the other (saved personal syntactic preferences)?
Whichever one fits your project.
It's both circumstantial and preferential.
Do you like shorter syntax and the features of the JQuery object? Then use JQuery.
On that note, JQuery is a subset of JavaScript, so in the background JQuery is doing the same thing that JavaScript is doing, just with an easier to understand and less cluttered syntax.
One difference between JavaScript createElement and innerHTML/JQuery in your example is that JQuery and innerHTML both require the provided HTML to be parsed, and then turned into DOM nodes, and then appended. Pure JavaScript will always be faster in that scenario,because you are skipping that parsing step, however, it's most likely a negligible difference in performance.
It really all comes down to what you're comfortable with and how concerned you are with optimizing your code for performance - and in this case I would venture to say that if you did decide to use createElement because of performance, it could be considered a superfluous optimization.
After months of web-development, I find myself completely helpless trying to find a good solution for a simple problem of formatting all the numbers throughout the DOM as I wish. Specifically, I have a js function my_int_formatter(), that I want to apply to all integers after the doc has been loaded. Best descriped by example - I want to do something like
<td>my_int_formatter({{django_variable}})</td>
I know the code above won't work, because I have to include 'script' tag, but first, I don't like the messy code, and second, javascript won't recognize python variable
I tried the following way:
HTML
<td class = 'my_integer'>{{django_variable}}</td>
JS
$(document).ready(function(){
// ....
content = $('.my_integer').html();
$('.my_integer').html(my_int_formatter(content));
...but as expected, I got wrong results because the js code applied the same html() content of the first .my_integer element in the DOM chain to all the others. Any ideas how to do this the short and correct way ?
If I understand correctly, your problem isn't with the formatting but actualy applying the formatting to each of your dom elements.
Try using jquerys .each() function and using $(this).html() to actualy grab the content.
$('.my_integer').each(function(){
content = $(this).html();
$(this).html(content+"formatted");
});
here's a quick fiddle :
https://jsfiddle.net/57rdq2a0/2/
If I understand you correctly, you want to use builtin django.contrib.humanize application: https://docs.djangoproject.com/en/1.9/ref/contrib/humanize/
You can format integers using some predefined filters, for example intcomma:
4500 becomes 4,500.
45000 becomes 45,000.
450000 becomes 450,000.
4500000 becomes 4,500,000.
Usage in your case would be like
{% load humanize %}
<td>{{django_variable|intcomma}}</td>
Also don't forget to include the app in INSTALLED_APPS
Also this question might be useful
If you want to apply filter to all variables of some kind, I suggest you to use Middleware to fiddle with response before rendering.
I currently have a bunch of lines that look like:
txt = "Can't print the value for <span class='keyword'>"+arguments[1]+"</span> before it's set";
I'm then doing
$('#mydiv').append($('<div/>').html(txt));
This looks terrible and I need to escape any html inside arguments[1]
The only alternative I can think of is to make sure all the text is inside its own element:
var spans = [];
spans[0] = $('<span/>').text("Can't print the value for ");
spans[1] = $('<span/>').text(arguments[1]).className('keyword');
spans[2] = $('<span/>').text(" before it's set");
$('#mydiv').append($('<div/>').append(spans[0],spans[1],spans[2]));
This is quite a lot for just a simple line of text. Is there anything else I can do?
edit: This isn't something that should be handled by a templating engine. It's html generated by a javascript logging function.
If It's a consistent format, I'd add it as a normal string and then do a search for the keyword part.
$('<div/>')
.appendTo('#mydiv')
.html("Can't print the value for <span class='keyword'></span> before it's set")
.find('.keyword').text(arguments[1]);
If you will be continuing to create lots of HTML using JS, I would suggest working with a templating library. I am a recent convert, it took me a long time to understand the point. But seeing many successful sites (twitter,github,etc.) and the great John Resig promote and/or make heavy use of templating, i'm glad I stuck with trying to understand. Now I get it. It's for separation of concerns, keeping logic out of the view.
I'm using this very bare bones templating library: http://blueimp.github.com/JavaScript-Templates/ though the templating provided by underscore.js and mustache.js are more popular.
The advantage of the library i'm using is its really small, <1kb and is basically like writing php/asp code if you are familiar with those.
you can write HTML inside <script> tags without having to escape:
using your variable, txt, the syntax looks like this:
<script>
var data={txt : "Can't print the value for <span class='keyword'>"+arguments[1]+"</span> before it's set"};
<div>{%=o.txt%}</div>
</script>
$('#element').method();
or
var element = $('#element');
element.method();
Without using a profiler, everyone is just guessing. I would suspect that the difference is so small it isn't worth worrying about. There are small costs to the second above the first like having to preform a lookup to find 'var element' to call the method on, but I would have thought finding '#element' and then calling the method is far more expensive.
However, if you then went on to do something else with element, the second would be faster
//Bad:
$('#element').foo();
$('#element').bar();
//Good:
var e = $('#element');
e.foo();
e.bar();
If you were using a loop where the value of $('#element') was used a lot, then caching it as in the 2nd version before the loop would help a lot.
For just this small snippet, it makes little difference.
Lookups via id (#) are pretty fast. I just tested your scenario on a small page with 2 div tags. Here is the code i used
var x = $("#div1");
var y = $("#div2");
var z = $("#div1");
every lookup took about 0.3ms on my laptop. The 2nd lookup for div1 executed the same internal jQuery methods as the first - indicating that there is no caching of already looked up objects
Performance becomes a bigger problem when you use other selectors like classname or more advanced jQuery selectors. I did some analysis on jQuery Selector Performance - check it out - hope it is helpful.
If you run only this code, no one should realy be faster. The second one might need more memory (because of the additional variable created).
If you want to be sure, why not test it yourself using a small selfwritten benchmark?
I think $('#element').method(); does not need as much memory as
var element = $('#element');
... because you bind #element to a variable.
Juste fore funne
\Indifferent:
$('#element').foo().bar();
This question already has answers here:
Deep cloning vs setting of innerHTML: what's faster?
(2 answers)
Closed 8 years ago.
I'm looking at a problem that needs a complex block of divs to be created once for each element in a set of ~100 elements.
Each individual element is identical except for the content, and they look (in HTML) something like this:
<div class="class0 class1 class3">
<div class="spacer"></div>
<div id="content">content</div>
<div class="spacer"></div>
<div id="content2">content2</div>
<div class="class4">content3</div>
<div class="spacer"></div>
<div id="footer">content3</div>
</div>
I could either:
1) Create all the elements as innerHTML with string concatenation to add the content.
2) Use createElement, setAttribute and appendChild to create and add each div.
Option 1 gets a slightly smaller file to download, but option 2 seems to be slightly faster to render.
Other than performance is there a good reason to go via one route or the other? Any cross-browser problems / performance gremlins I should test for?
...or should I try the template and clone approach?
Many thanks.
Depends on what's "better" for you.
Performance
From a performance point of view, createElement+appendChild wins by a LOT. Take a look at this jsPerf I created when I compare both and the results hit in the face.
innerHTML: ~120 ops/sec
createElement+appendChild: ~145000 ops/sec
(on my Mac with Chrome 21)
Also, innerHTML triggers page reflow.
On Ubuntu with Chrome 39 tests get similar results
innerHTML: 120000 ops/sec
createElement: 124000 ops/sec
probably some optimisation take place.
On Ubuntu with QtWebkit based browser Arora (wkhtml also QtWebkit) results are
innerHTML: 71000 ops/sec
createElement: 282000 ops/sec
it seems createElement faster in average
Mantainability
From a mantainability point of view, I believe string templates help you a lot. I use either Handlebars (which I love) or Tim (for project which need smallest footprints). When you "compile" (prepare) your template and it's ready for appending it to the DOM, you use innerHTML to append the template string to the DOM. On trick I do to avoid reflow is createElement for a wrapper and in that wrapper element, put the template with innerHTML. I'm still looking for a good way to avoid innerHTML at all.
Compatibility
You don't have to worry here, both methods are fully supported by a broad range of browsers (unlike altCognito says). You can check compatibility charts for createElement and appendChild.
Neither. Use a library like jQuery, Prototype, Dojo or mooTools because both of these methods are fraught with trouble:
Did you know that innerHTML on tables for IE is readonly?
Did you know for the select element it's broken as well?
How about problems with createElement?
The writers of the major javascript libraries have spent a lot of time and have entire bug tracking systems to make sure that when you call their DOM modifying tools they actually work.
If you're writing a library to compete with the above tools (and good luck to you if you are), then I'd choose the method based on performance, and innerHTML has always won out in the past, and since innerHTML is a native method, it's a safe bet it will remain the fastest.
altCognito makes a good point - using a library is the way to go. But if was doing it by hand, I would use option #2 - create elements with DOM methods. They are a bit ugly, but you can make an element factory function that hides the ugliness. Concatenating strings of HTML is ugly also, but more likely to have security problems, especially with XSS.
I would definitely not append the new nodes individually, though. I would use a DOM DocumentFragment. Appending nodes to a documentFragment is much faster than inserting them into the live page. When you're done building your fragment it just gets inserted all at once.
John Resig explains it much better than I could, but basically you just say:
var frag = document.createDocumentFragment();
frag.appendChild(myFirstNewElement);
frag.appendChild(mySecondNewElement);
...etc.
document.getElementById('insert_here').appendChild(frag);
Personally, I use innerHTML because it's what I'm used to and for something like this, the W3C methods add a lot of clutter to the code.
Just a possible way to cut down on the number of div's however, are there any reasons you are using spacer elements instead of just editing the margins on the content divs?
I don't think there's much to choose between them. In the olden days (IE6, FF1.5), innerHTML was faster (benchmark), but now there doesn't seem to be a noticeable difference in most cases.
According to the mozilla dev. docs there are a few situations where innerHTML behaviour varies between browsers (notably inside tables), so createElement will give you more consistency - but innerHTML is usually less to type.
Since you mentioned template and clone, you may be interested in this question:
Deep cloning vs setting of innerHTML: what’s faster?
Another option is to use a DOM wrapper, such as DOMBuilder:
DOMBuilder.apply(window);
DIV({"class": "class0 class1 class3"},
DIV({"class": "spacer"}),
DIV({id: "content"}, "content"),
DIV({"class": "spacer"}),
DIV({id: "content2"}, "content2"),
DIV({"class": "class4"}, "content3"),
DIV({"class": "spacer"}),
DIV({id: "footer"}, "content3")
);
Personally, if each item is going to need the exact same structure created I would go with the cloning approach. If there's any logic involved in creating the structure into which the content will go, I'd rather maintain something like the above than fiddling about with strings. If that approach turned out to be too slow, I'd fall back to innerHTML.
Neither. Use cloneNode.
var div = document.createElement('div');
var millionDivs = [div];
while (millionDivs.length < 1e6) millionDivs.push(div.cloneNode())
As I know, the fastest way is to evade DOM editing as long as it is possible. That mean, it is better to create a big string and then put it into innerHTML. But there is a remark for this: don't make too many operation on big strings, it is faster to use array of strings and then join them all.
For a complex problem like this, I usually use the innerHTML methods because they are a)easier to read and modify code-wise b)more convenient to use in loops. As the top post says, they unfortunately fail in IE(6,7,8) on <table>, <thead>,<tbody>,<tr>,<tfoot>, <select>, <pre> elements.
1) Create all the elements as innerHTML with string concatenation to add the content.
2) Use createElement, setAttribute and appendChild to create and add each div.
3) compromise. Create all the elements in one go as innerHTML (which avoids a lot of childnode list manipulation slowness), then write the content that changes on each item using data/attribute access (avoiding all that nasty mucking around with having to HTML-escape content). eg. something like:
var html= (
'<div class="item">'+
'<div class="title">x</div>'+
'<div class="description">x</div>'+
'</div>'
);
var items= [
{'id': 1, 'title': 'Potato', 'description': 'A potato'},
{'id': 2, 'title': 'Kartoffel', 'description': 'German potato'},
// ... 100 other items ...
];
function multiplyString(s, n) {
return new Array(n+1).join(s);
}
var parent= document.getElementById('itemcontainer');
parent.innerHTML= multiplyString(html, items.length);
for (var i= 0; i<items.length; i++) {
var item= items[i];
var node= parent.childNodes[i];
node.id= 'item'+item.id;
node.childNodes[0].firstChild.data= item.title;
node.childNodes[1].firstChild.data= item.description;
}
Can also be combined with Neall's tip about DocumentFragments.