Jeffery Thomas
Jeffery Thomas

Reputation: 42598

Why does DOM appendChild() fire on('load', ...) but jQuery append() does not?

I have the following to snippets of code:

$(document).ready(function() {
    document.head.appendChild(
        $('<script />').attr('src', 'source.js').on('load', function() {
            ...
        })[0]
    );
});

This will fire the load handler.

Whereas using the normal jQuery append():

$(document).ready(function() {
   $('head').append(
        $('<script />').attr('src', 'source.js').on('load', function() {
            ...
        })
    );
});

This will not fire the load hander.

What am I missing: why does jQuery append() not work?

Is using document.head.appendChild() a bad idea?

NOTE: I can't use $.getScript(). The code will run on a local file system and chrome throws cross site script errors.


Update

Some people had trouble reading the compact style, so I used extra line feeds to clarify which objects where calling which methods. I also made it explicit that my code is inside a $(document).ready block.


Solution

In the end I went with:

$(document).ready(function() {
    $('head')[0].appendChild(
        $('<script />').attr('src', 'source.js').on('load', function() {
            …
        })[0]
    );
});

I think @istos was right in that something in domManip is breaking load.

Upvotes: 1

Views: 3673

Answers (4)

Muhammad Umer
Muhammad Umer

Reputation: 18117

you don't have to ditch jquery completely, you could use zeptojs. Secondly, I couldn't find out how and why exactly this behavior is happening. Even though i felt answer was to be found in links below. So far i can tell that if you insert element before definig src element then load won't fire.

But for manual insertion it doesn't matter. (????)

However, what i was able to discover is that if you use appendTo it works. Code :http://jsfiddle.net/techsin/tngxnkk7/

var $ele = $('<script />').attr('src', link).load(function(){ abc(); }) ).appendTo('head');

New Info: As is understood adding script tag to dom with src attribute on it, initiates the download process of script mentioned in src. Manual insertion causes page to load external script, using append or appendTo causes jquery to initiate downloading of external js file. But event is attached using jquery and jquery initiates download then event won't fire. But if it's the page itself initiates the download then it does. Even if event is added manually, without jquery, adding via jquery to dom won't make it fire.

Links in which i think should be the answer...

Append Vs AppendChild JQuery

http://www.blog.highub.com/javascript/decoding-jquery-dommanip-dom-manipulation/

http://www.blog.highub.com/javascript/decoding-jquery-dommanip-dom-manipulation/

https://github.com/jquery/jquery/blob/master/src/manipulation.js#L477-523

http://ejohn.org/blog/dom-documentfragments/

Upvotes: 0

Lakmal Caldera
Lakmal Caldera

Reputation: 1031

You should probably make sure that the jquery append is fired when the document is ready. It could be that head is not actually in the dom when the append fires.

Upvotes: 0

istos
istos

Reputation: 2662

jQuery is doing some funny business in its DOM manipulation code. If you look at jQuery's source, you'll see that it uses a method called domManip() inside the append() method.

This domManip() method creates a document fragment (it looks like the node is first appended to a "safe" fragment) and has a lot of checks and conditions regarding scripts. I'm not sure why it uses a document fragment or why all the checks about scripts exist but using the native appendChild() instead of jQuery's append() method fires the event successfully. Here is the code:

Live JSBin: http://jsbin.com/qubuyariba/1/edit

  var url = 'http://d3js.org/d3.v3.min.js';  
  var s = document.createElement('script');
  s.src = url;
  s.async = true;

  $(s).on('load', function(e) {
    console.log(!!window.d3); // d3 exists
    $(document.body).append('<h1>Load fired!</h1>');
  });

  $('head').get(0).appendChild(s);


Update:

appendChild() is a well supported method and there is absolutely no reason not to use it in this case.

Upvotes: 1

Abruzzi
Abruzzi

Reputation: 495

Maybe the problem is when you choose DOM appendChild, actually you called the function is document.on('load',function(){});, however when you choose jQuery append(), your code is $('head').on('load', function(){}).

The document and head are different.

You can type the code below: $(document).find('head').append($('<script />').attr('src', 'source.js').end().on('load', function() { ... }));

Upvotes: 0

Related Questions