3

After dynamically appending a chunk of HTML to a document (Example uses jQuery, but question is valid for all JavaScript), can I assume that the appended elements are available immediately afterwards?

$('#content').append('<p>Content</p><button id="newbutton">New</button><p>Some more content</p>');
var forExample = $('#newbutton').width(); // Element available?

In my particular case, creating single elements is not practicable. Also, this is long past the document.ready event.

Christian Studer
  • 24,947
  • 6
  • 46
  • 71
  • 2
    Couldn´t you answer that question yourself by just testing it? – Amberlamps Nov 16 '12 at 09:58
  • 2
    Testing it would involve loads of browsers (IE, Opera, FF, Chrome, Safari, Konqueror, ...) in loads of version on loads of devices (PC, iPhone, Android, Windows Phone, Bada, ...). – Marcus Riemer Nov 16 '12 at 10:07
  • Note that calculating computed width fails on hidden elements (using `display:none`). – David Hellsing Nov 16 '12 at 10:13
  • @Amberlamps: This particular bit of code would have been easy to test, except that I was worried about concurrency issues. I.e. if you use code accessing the DOM tree without waiting for the document.ready-event, sometimes it works and sometimes it doesn't. (Depends on cache state, computer speed, browser implementation.) So you never really be sure until you've hit the second case at least once. – Christian Studer Nov 16 '12 at 11:12

2 Answers2

3

Yes, they're available immediately. jQuery will return you the correct objects, for example, and you may bind elements onto them.

But as they're not rendered while your script is running, size computations aren't always immediately made, so if you need the dimensions of the objects you might have to do

setTimeout(function(){
    var forExample = $('#newbutton').width();
    // use size
}, 0); // 0 is enough to tell the engine to render before it executes the callback

Note that the behavior of browser is different if you're incrementally debugging (the script isn't really "running").

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • You don't have to do `setTimeout` to get `.width()`. The browser will calculate when the call is made if necessary. – Esailija Nov 16 '12 at 10:02
  • Note that the minimum delay for `setTimeout` in HTML5 is 4ms, so `0` is not representative for what is actually happening. I believe that what you are doing is just downgrading the execution stack. – David Hellsing Nov 16 '12 at 10:05
  • @dystroy That's very vague.. maybe if the element is a loading image and you get lucky with it just being loaded after a setTimeout. But there is no way you normally need a timeout to get a correct width. – Esailija Nov 16 '12 at 10:12
  • @Esailija It's vague because it's a "sometimes" : I fixed some dimension computation bugs using this trick (not recently). I even answered a question with this. I'm trying to find some cases where it's needed. – Denys Séguret Nov 16 '12 at 10:14
  • @christian I see you accepted my answer but I'm a little worried because I can't reproduce the "width not available" problem on my current Chrome. I'm not sure it's still needed to use the trick I describe. It may depend on the browser though. – Denys Séguret Nov 16 '12 at 11:14
  • @Esailija Not 100% the same thing (not an addition but a css change), [this](http://jsfiddle.net/kPZ3E/) is an example of some code in which you have to use setTimeout (in Chrome) to let the browser render before you can get the correct width. This is for an answer I just made to [this question](http://stackoverflow.com/questions/13416673/javascript-convert-width-and-height-to-font-size). – Denys Séguret Nov 16 '12 at 12:52
  • @dystroy can you reproduce in a simpler example? Works fine with this http://jsfiddle.net/BPYCE/3/ – Esailija Nov 16 '12 at 13:00
  • It works. But the fiddle in my previous comment crashes (full stack because of recursion) when I test it on my chromium/linux without the timeout. It's not 100% reproducible. There may be a race issue but I never dived in Chromium source. – Denys Séguret Nov 16 '12 at 13:02
  • @dystroy yes in your example the timeout allows visual paints to happen but that has nothing to do with `.width()` reporting correctly. The browser can calculate `.width()` without actually visually painting. – Esailija Nov 16 '12 at 13:04
  • @dystroy: The `.width()` call is just an example. You're all getting a little bit sidetracked. I was more interested on the existence of the DOM nodes ('#newbutton' and the others.) – Christian Studer Nov 16 '12 at 14:32
0

Yes, it's directly available. You could have tested it in 1min on fiddle... http://jsfiddle.net/adxbH/

var newButton = document.createElement('button');

newButton.id = 'newbutton';
newButton.innerHTML = 'button_test';
document.body.appendChild(newButton);
var forExample = document.getElementById('newbutton');
alert(forExample.offsetWidth);​

As you can see, also very easy without using jQuery.

leMoisela
  • 1,046
  • 8
  • 17