Reputation: 318638
I have the following code which loads an external script and is supposed to execute some code when it's loaded:
$('<script/>', {
type: 'text/javascript',
src: 'https://raw.github.com/einars/js-beautify/master/beautify.js'
}).on('load', function() {
alert('jsb loaded' + typeof js_beautify);
}).appendTo('body');
However, the event never fires - even though the script is properly loaded, as verified with
window.setTimeout(function() {
alert(typeof js_beautify);
}, 1000);
which alerts function
just fine.
Demo: http://jsfiddle.net/ThiefMaster/x2b9x/
Upvotes: 3
Views: 314
Reputation: 1435
(jQuery:2.0.3) 2 Reasons for the non-triggered load event on the dynamic script tag injection through appendTo():
getScript() use DOM function directly
document.head.appendChild( script[ 0 ] );
to inject the script tag element. This ensure the tag element is actually added into the DOM. While appendTo() will try to use Ajax to load the script from the source URL instead. Then the load event is triggered for window object instead of the script object.
The following is the detail testing on the jQuery.appendTo() to learn the reason
var $script = $("<script>", {
src: this.options.url_js,
"data-widget": this.widgetFullName,
type:"text/javascript"
}).on(
"load error",
function( evt ) {
script.remove();
if ( evt ) {
alert( evt.type === "error" ? 404 : 200, evt.type );
}
}
).appendTo("head");
jQuery.appendTo() is the alias to the "append". The actual code is
append: function() {
return this.domManip( arguments, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
var target = manipulationTarget( this, elem );
target.appendChild( elem );
}
});
}
Before actually inject the element into the DOM, it will use the domManip() to do some ajax stuff.
domManip: function( args, callback, allowIntersection ) {
There are 2 key variables in this function, 1 is "value", 2nd is "node". The "value" is the variable "$script". the actual injected element is the "node", which is not the "$script"
callback.call( this[ i ], node, i ); //inject the element into the DOM
That is why the "load" event handler on the "$script" won't be invoked at all.
But this load event will be triggered twice, 1 is for the loaded element, (here is the node), another one is for the window object. If your handler is hooked on the window object, it will be invoked.
Upvotes: 2
Reputation: 887867
You should call $.getScript()
, which does exactly that, and works correctly.
Upvotes: 2