I have a javascript function I'm writing which is being used to include an external JS file, but only once. The reason I need such a function is because it is being called when some content is loaded via AJAX and I need to run page-specific code to that content (no, just using .live
won't cover it).
Here's my attempt, shortened for brevity:
$.include_once = function(filename) {
if ($("script[src='" + filename + "']").length === 0) {
var $node = $("<script></script>")
.attr({
src : filename,
type : "text/javascript"
})
;
$(document.body).append($node);
}
};
This works fine: the function is called, it loads the external file, and that file is being run when loaded. Perfect.
The problem is that it will always re-load that external file: the query I'm using to check for the presence of the script always finds nothing!
When debugging this, I added some lines:
alert($("script").length); // alerts: 4
$(document.body).append($node);
alert($("script").length); // alerts: 4
Looking in the dynamic source (the HTML tab of Firebug), I can't find the script tag at all.
I know that I could maintain an array of files that I've previously included, but I was hoping to go with a method such as this, which (if it worked), seems a bit more robust, since not all the JS files are being included in this way.
Can anyone explain the behaviour seen in this second snippet?
Dynamic loadingThose files can be loaded asynchronously in JavaScript. To load a JavaScript file dynamically: Create a script element. Set the src , async , and type attributes.
You should put your JS code in a separate file because this makes it easier to test and develop. The question of how you serve the code is a different matter.
1 - You can load it with an AJAX call then use eval. This is the most straightforward way but it's limited to your domain because of the Javascript safety settings, and using eval is opening the door to bugs and hacks. 2 - Add a script element with the script URL in the HTML.
To include an external JavaScript file, we can use the script tag with the attribute src . You've already used the src attribute when using images. The value for the src attribute should be the path to your JavaScript file. This script tag should be included between the <head> tags in your HTML document.
jQuery is a bit of a dumb-dumb in this case; it doesn't do at all what you'd expect. When you append($node)
jQuery does this:
jQuery.ajax({
url: $node.src,
async: false,
dataType: "script"
})
Woops! For local files (eg on the same domain) jQuery performs a standard XMLHttpRequest
for the .js file body, and proceeds to "eval" it by a whole convoluted process of creating a <script>
tag (again!) and settings it's contents to your .js file body. This is to simulate eval
but in the global context.
For cross-domain files, since it cannot perform the standard XMLHttpRequest
due to the same-domain policy, jQuery once again creates a <script>
element and inserts it into <head>
.
In both the local and cross-domain cases above jQuery finally gets around to doing this:
head.removeChild(script);
And booms your .length
check! Bummer.
So on to your problem, don't bother jQuery with this. Just do
document.getElementsByTagName('head')[0]
.appendChild(
document.createElement('script')
)
.src = filename;
Which will do what you'd expect, particularly wrt querying for it later.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With