This question already has answers here:
How do I include a JavaScript file in another JavaScript file?
(70 answers)
Closed 9 years ago.
I'd like to know if it is possible to include a .js file within another .js file?
The reason for me wanting to do this is to keep client includes to a minimum. I have several .js files already written with functions that are needed by the client. The client would have an html file which he/she manages with a .js file include (my .js file).
I could re-write a new .js file with all the functions in it or, to avoid doing double work, figure out a way to write a .js file that includes other .js files.
I basically do like this, create new element and attach that to <head>
var x = document.createElement('script');
x.src = 'http://example.com/test.js';
document.getElementsByTagName("head")[0].appendChild(x);
You may also use onload event to each script you attach, but please test it out, I am not so sure it works cross-browser or not.
x.onload=callback_function;
The best solution for your browser load time would be to use a server side script to join them all together into one big .js file. Make sure to gzip/minify the final version. Single request - nice and compact.
Alternatively, you can use DOM to create a <script> tag and set the src property on it then append it to the <head>. If you need to wait for that functionality to load, you can make the rest of your javascript file be called from the load event on that script tag.
This function is based on the functionality of jQuery $.getScript()
function loadScript(src, f) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.src = src;
var done = false;
script.onload = script.onreadystatechange = function() {
// attach to both events for cross browser finish detection:
if ( !done && (!this.readyState ||
this.readyState == "loaded" || this.readyState == "complete") ) {
done = true;
if (typeof f == 'function') f();
// cleans up a little memory:
script.onload = script.onreadystatechange = null;
head.removeChild(script);
}
};
head.appendChild(script);
}
// example:
loadScript('/some-other-script.js', function() {
alert('finished loading');
finishSetup();
});
There is no straight forward way of doing this.
What you can do is load the script on demand. (again uses something similar to what Ignacio mentioned,but much cleaner).
Check this link out for multiple ways of doing this:
http://ajaxpatterns.org/On-Demand_Javascript
My favorite is(not applicable always):
<script src="dojo.js" type="text/javascript">
dojo.require("dojo.aDojoPackage");
Google's closure also provides similar functionality.
A popular method to tackle the problem of reducing JavaScript references from HTML files is by using a concatenation tool like Sprockets, which preprocesses and concatenates JavaScript source files together.
Apart from reducing the number of references from the HTML files, this will also reduce the number of hits to the server.
You may then want to run the resulting concatenation through a minification tool like jsmin to have it minified.
I use #gnarf's method, though I fall back on document.writelning a <script> tag for IE<7 as I couldn't get DOM creation to work reliably in IE6 (and TBH didn't care enough to put much effort into it). The core of my code is:
if (horus.script.broken) {
document.writeln('<script type="text/javascript" src="'+script+'"></script>');
horus.script.loaded(script);
} else {
var s=document.createElement('script');
s.type='text/javascript';
s.src=script;
s.async=true;
if (horus.brokenDOM){
s.onreadystatechange=
function () {
if (this.readyState=='loaded' || this.readyState=='complete'){
horus.script.loaded(script);
}
}
}else{
s.onload=function () { horus.script.loaded(script) };
}
document.head.appendChild(s);
}
where horus.script.loaded() notes that the javascript file is loaded, and calls any pending uncalled routines (saved by autoloader code).
Related
now, this question has been asked and answered successfully many times, yet none of the things i try work.
I have tried head.js & require.js libraries
I have also tried
if (!window.unique_name) {
unique_name = true;
//code here..
}
none of which I can get to work (the global variable is always undefined)
the script I am trying to include runs something like this:
//clock.js
clockyTick = function() {
//my code here
}
setInterval(clockyTick, 1000);
the apps that call this script, standalone, work fine.
only when both apps are included on the same page (via calls to PHP require()) they break.
Here is the cause of the problems (I think):
I am building custom web apps on a (Joomla) site and have the requirement of displaying two of my apps on the same page.
Both apps need the same .js file to operate correctly, which works fine when they run standalone, but as soon as both apps are running on the same page (in the admin section) the scripts conflict and stop each other from working
(the script in question is a dynamic clock script that grabs the specialised contents of a div and modifies it to something else)
I think the reason I cannot get aforementioned libraries to work, is the fact that they also are being included twice on the admin page.
is there any way around this, or do I have to bite the bullet and integrate a library into the main Joomla template? (meaning the library is uselessly loaded on every single page, yet only used on 3 of hundreds)
jQuery is also required, separately, on each app..but thankfully I am able to use noConflict to avoid problems there (not ideal)
The joomla way would be to instantiate the document inside your module and unset only the conflicting script as described in this question here just before you load the module's script:
1) get an instance if the document object and remove the js files (you
could do that in a plugin) :
<?php
//get the array containing all the script declarations
$document = JFactory::getDocument();
$headData = $document->getHeadData();
$scripts = $headData['scripts'];
//remove your script, i.e. mootools
unset($scripts['/media/system/js/mootools-core.js']);
unset($scripts['/media/system/js/mootools-more.js']);
$headData['scripts'] = $scripts;
$document->setHeadData($headData);
?>
Or in your case, I think you could try the dirty solution below inside your js files:
//1st module script
var unique_name;
if (unique_name == false || unique_name == null) {
unique_name = true;
//code here..
alert("Included 1st script");
}else{
//do nothing
alert("Not included 1st script")
}
//2nd module script
var unique_name;
if (unique_name == false || unique_name == null) {
unique_name = true;
//code here..
alert("Included 2nd script");
}else{
//do nothing
alert("Not included 2nd script")
}
Here is a DEMO
If you are having conflicts with PHP require(), you can try require_once(). However, as mentioned, that’s not the Joomla way of doing things.
IE7 gives the following error: 'myapp' is undefined
//home.html
<script type="application/x-javascript" src="//www.mysite.com/myjs.js"></script>
<script type="text/javascript" charset="utf-8">
new myapp.myfunc();
</script>
javascript file:
//myjs.js
myapp = {
myfunc : function(){
alert('hello world');
}
};
*I understand there are many ways to rewrite the code that is used on home.html, but I want to make this work without changing that. I found a working example with similar structure and no JS errors (IE7, IE6). https://google-developers.appspot.com/custom-search-ads/docs/sample
EDIT:
The < script > code will be given to external clients, so I want to keep it as simple as possible. See example link.
Occam's razor suggests that either IE/MSHTML does not support script elements with type="application/x-javascript". That might have to do with the fact that application/x-javascript is not a registered MIME media type, nor was it ever necessary.
Or it has to do with the fact that //www.mysite.example.com/myjs.js is not a supported URI-reference in that environment. Use fully-qualified URIs like http://www.mysite.example.com/myjs.js instead. (And please use the registered example domains for examples.)
You should also declare identifiers that you intend to use as variables:
var myapp = {
…
};
If you do not do this, problems can occur if there is an element named myapp in the document. In JScript/MSHTML, identifier resolution will find a host object in the scope chain that has myapp as its property. The value of that property will be a reference to the corresponding element object, and attempting to overwrite that property value will cause a runtime error.
Add an event handler to the body's Load event. In that event handler, make your myapp.myfunc() call.
Whenever you're making your code available for consumption, you always want to make sure you're being a good citizen on the page. That means you don't want to create unnecessary global variables, and make sure ones you do create are unique enough. Thats why it's a good idea to wrap your code in an immediately-invoked function expression.
Also, it's generally just easier to do the whole thing with javascript. This is how Google analytics and Facebook plugins load their code.
<script type="text/javascript">
(function() {
var loadScript = function(src, callback) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
// modern browsers
script.onload = callback;
// IE 6 & 7
script.onreadystatechange = function() {
if (this.readyState == 'complete') {
callback();
}
}
head.appendChild(script);
};
loadScript('path/to/myscript.js', function() {
//script loaded
});
})();
</script>
I have 4 javascript files (each for a single HTML file) and 3 functions are THE SAME in all 4 files.
I'd like to find a smooth solution that I could somehow include these 3 functions separately... is it possible to include .js within a .js?
You can have multiple <script> tags:
<script src="lib.js"></script>
<script>
// do stuff
</script>
You can use jQuery:
$.getScript("lib.js", function() {
// do stuff
});
You can use a pre-processor like browserify or YUICompressor or Google's Closure Compiler.
You can write this by your own, for example as it works in google analytics:
(function(){
var lastIncludedScript = document.getElementsByTagName('script')[0];
var yourScript = document.createElement('script');
yourScript.type = 'text/javascript';
yourScript.src = 'path/to/script.js';
lastIncludedScript.parentNode.insertBefore(yourScript, lastIncludedScript);
})();
or as in function:
function includeScript( path ){
var lastIncludedScript = document.getElementsByTagName('script')[0];
var yourScript = document.createElement('script');
yourScript.type = 'text/javascript';
yourScript.src = path;
lastIncludedScript.parentNode.insertBefore(yourScript, lastIncludedScript);
}
usage:
includeScript( 'path/to/script.js' );
You can have a look at this nice explanation about loading javascript files asynchronously. This could solve your problem. Or look at this stack overflow question on how to load javascript files inside other javascript files.
However it may be worth a shot to include everything you use in one single javascript file and load the same one on every site. This improves performance because only one http request has to be made to load all javascript and it can be cached very efficiently (so no need to load any javascript later on).
Use proper js file required in each html file. That will solve your issue. Also the one contating the general functions can be added for both html files. This should solve your problem.
It's a bit slow to include files from other JavaScript in the browser. I would write a server-side script to combine and minify all relevant JavaScript into one "file" to be sent to the client.
Your pages can pass parameters to this script to choose what needs to be included.
I'm having a very frustrating problem with my javascript files. I have one global namespace that contains a page_data, utilities, modules etc namespace.
My directories look like this:
/utilities/single_utility.js
/modules/module.js etc tec
Anyways, I load the utilities before the modules, (which use the utilities) but keep getting problems.
My loader script looks like this (its wrapped in an SEAF):
for (var index in file_list) {
var url = file_list[index];
var new_script = document.createElement('script');
new_script.setAttribute("type", "text/javascript");
new_script.setAttribute("src", url);
element.appendChild(new_script);
}
Project is my global namespace, that holds all of these other namespaces. But when I try to reference a utility in one of my modules, with Project.utilities.session.exist() etc, it will sometimes throw an error that Project can't be found?
How can I fix this to make sure my files are loading properly or am I doing something else wrong?
Using async = false should protect your load order.
This is a quick snippet I use to load and maintain order.
var loadScript = function( url ) {
if (url) {
var doc = document,
t = doc.createElement("script"),
s = doc.getElementsByTagName("script")[0];
t.type = "text/javascript";
// Keep script order!
t.async = false;
t.src = url;
s.parentNode.insertBefore(t, s);
}
};
Some references backing this logic (and regarding browser support) from MDN and Microsoft
When you add the script tag to the page, the browser has to go out and download those scripts. There's no guarantee that they will download and execute in the same order that you created them.
You will need to add an event listener to new_script for when it loads, either onload or onreadystatechange, depending on the browser. But truly I'd recommend using a script loading library (such as RequireJS) that handles all the nasty details for you.
As an aside, why not just add all your script tags directly to your page? In that case they load sequentially.
It's better if you resolve this problem using a script loader.
As Matt said RequireJS is a good option if you also want to handle script dependencies.
For script loading only, you can take a look into LAB.js, is very small and straightforward:
for (var index in file_list) {
$LAB.script(file_list[index]);
}
If the scripts have dependencies and must be loaded in order, you can use .wait(), to do that keep the chain object returned by script. You can re-write the loop to keep the chain:
var chain;
for (var index in file_list) {
if (!chain) {
chain = $LAB.script(file_list[index]).wait();
} else {
chain.script(file_list[index]).wait();
}
}
Or just forget the file_list array and use $LAB directly:
$LAB.script('file1.js').wait()
.script('file2.js').wait()
/* ... */
I believe the issue below relates to variable scope, although I may be mistaken.
I've created a javascript bookmarklet that inserts a few external javascript files into the web page. For this bookmarklet, I need to insert 3 external js files. To insert these files, I'm using about 6 different functions, all that are very similar. I tried to create a new function to consolidate these functions, but it keeps failing. I believe it fails because of a variable scope issue, but I may be mistaken.
Here is the code that works to insert one (of 3) external js files:
jQueryCheck();
function jQueryLoader() {
var jQ = document.createElement('script');
jQ.type = 'text/javascript';
jQ.onload = jQueryCheck;
jQ.src = 'http://example.com/jquery.js';
document.body.appendChild(jQ); //the jQuery variable get defined here
}
function jQueryCheck() {
if (typeof jQuery == 'undefined') {
jQueryLoader();
} else {
tableSorterLoader();
}
}
The above code works, but I have to run nearly identical functions 3 times in order to insert 3 separate external files. I tried to consolidate the code into the following (which fails):
var scripts = [];
scripts[0] = 'http://example.com/jquery.js';
scripts[1] = 'http://example.com/plugin2.js';
scripts[2] = 'http://example.com/plugin3.js';
jsLoader(scripts, mainFunction);
function jsLoader(file,nextFunction) {//nextFunction is the function that runs after jsLoader is finished
for (var i = 0; i <= scripts.length; i++) {
function insertScript() {
var js = document.createElement('script');
js.type = 'text/javascript';
js.onload = scriptCheck;
js.src = file[i];
document.body.appendChild(js);//the jQuery variable fails to get defined here
}
function scriptCheck() {
var variableTest = (typeof jQuery);
if (typeof jQuery == 'undefined') {
insertScript();
}
}
scriptCheck();
}
nextFunction();
}
I believe I isolated where the problem occurs: after document.body.appendChild(js); (see the comments). In the first set of functions, the jQuery variable is successfully defined at this line of code (because the jQuery library is inserted). However, in the second function, the jQuery variable is not getting defined even though the jQuery library still is being successfully inserted into the web page's html. It is necessary to validate whether jQuery has been defined so that the remainder of the code does not execute until jQuery is active and available.
Can anyone suggest some causes to this problem as well as the solutions? Additionally, can anyone suggest improvements to my new function jsLoader() to make it more intelligent/professional?
It looks like you need the jquery file loaded before the plugins will work, so I would not try to load all three at once (like the second code is trying), but to approach it probably like what the initial 3 function calls did (maybe).
As the comments suggest, I would not use a loop (unless you have many plugin files), but rather use an un-nested loading function like jsLoader. The first call loads jQuery with nextFunction calling jsLoader for the first plugin file with it's nextFunction calling the last file. Then you know when you files are all loaded.