3.2.0

dynamic load javascript from javascript

i just want to share a small code sequence, that changed the way of programming in Javascript for me:

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'snip.js';
document.getElementsByTagName('head')[0].appendChild(script);


You can load fresh (even dynamic generated) code within javascript and it will parsed.

Andres Obrero
July 19,
XMLHttpRequest is more suited for use with the grid

but yes it's a handy thing to do
July 19,
you are right. XMLHttpRequest is better for data but in the code itself
Alex use
$import("controls/grid.js");
$import("http/request.js");
...
...
//	------------------------------------------------------------

function $import(path){
    var i, base, src = "grid.js", scripts = document.getElementsByTagName("script");
    for (i=0; i<scripts.length; i++){if (scripts[i].src.match(src)){ base = scripts[i].src.replace(src, "");break;}}
    document.write("<" + "script src=\"" + base + path + "\"></" + "script>");
}

and that can load code only before finishing the page.
My suggestion (well it comes from Martin Honnen) is a dynamic way to load code jsut before needed.
You can create libraries.
Andres Obrero [Winterthur]
July 20,
Hello Andreas,

great code!

Does the code load every time the sequence is run? So is the loaded file cached by the browser or is it bypassing the cache?

Thank you.
Dietrich
July 20,
Yes I didn't mean is't a bad thing to do just meant it's better for data whice most people will do in here :)

I use it when I need to also use the other method if needed as well depends what you are doing.

with XMLHttpRequest you can just request a CSV/TSV file with data the populate the grid which is a smaller than making a javascript array server side and putting in page.
July 20,
Hallo Dietrich
i use it heavily to avoid traffic. Once a file has beed sent, the browser takes it from the cache.
i use it like
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'data.php?start=100&end=200';

and data.php delivers it in this way:
var data[[1,2,3],['u','w','v'],['a','b','c']....];

1) this is a extremely faster than csv or xml, as the code is pure js
and
2) the data can be cached.
The problem i still have to solve is, when data changed (some kind of tainting. There are php ways, but i'm still reading
Andres Obrero [Winterthur]
July 20,
If you change the query line in someway it will bypass the cache and retrieve your new data maybe use a date stamp or somthing in it.
July 21,
That is not a solution, because
a) javascript does not know, when data is tainted to request a new page
b) if it sends always a random pattern like timestamp, it cannot take advantage of the browser cache.

so there must be somekind of heartbeat-notification between js and php.

i'm thinking of an phpAddEventLister(). This way all js functions can be notified by one central channel.
Andres Obrero [Winterthur]
July 21,
not that I know of since you can't open a socket. I presume you are using AJAX then not requests for new pages?
July 21,
yup, sort of, i use it sync instead of async:

var api = new api("phpclass");
then i call
res = api.phpFunc(args);

where phpFunc is a truly php function.

This allows smooth and simple javascript.
You may access directly all php classes without forms and urls.
(similar to xml_rpc but without a wrapper)
But be warned: sync is only suitable for intranet.
On the other hand it gives you the power of php inside of javascript.
Andres Obrero [Winterthur]
July 21,
yeah I know what you mean like toxic

don't think you can be notified without peridically calling the server since that way of accessing php is like working offline there is no permanent connection

you could do a HEAD request to a php script I suppose which will cut down on network traffic but you still will have to prob the server for changes besides having a server connected to the client all the time wouldn't scale well anyway
July 21,
Yup,
HEAD requests reduce a bit the overhead. But if you listen to the traffic (etherreal or so) you see even sending headers only al lot of @sh#*%&*@# blocks.
One Test I did was: with a tiny java applet, keeping a UDP socket open.
Perfect in traffic, but not very handy in practice.
So no solution for a true code cleanup in sight, but at least very useful.
Andres Obrero [Winterthur]
July 21,
I personnaly can't think of a way appart from like you said using java and a socket but then you are relying on java vm been installed :(
July 21,
one idea i will test soon, is:
to use the readystate of a very slow file delivery with the method
described at the beginning of this thread.
Each browser have some timeout. Its not mature, but thinking of delaying php sending very small piceces of code over a long period, just to keep alive the stream.
A long time ago, this method was used for chatrooms in javascript. The disadvantage was the hourglass. But now it works in the background without notice.
Andres Obrero [Winterthur]
July 21,
Have a look at this site
http://www.pushlets.com/

It generates serverside notification events and can be traped in javascript. May be this is your answer

Thanks
Kini
Kini
July 21,
I think that is basically what andres said about doing :)
July 21,
How to connect to Mysql using JavaScript
Veena
November 10,
Hi, I've got a problem with this system. When I do that :

I'm in the file : general.js

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'snip.js';
document.getElementsByTagName('head')[0].appendChild(script);

and I have an alert('hello'); in snip.js , it works. Oh yeah, great... But if I have a function, let's say function getSomething() { }, I can't call it in general.js. That's strange. It means the script is executed, but functions are not reusable. Someone as an idea why ?

Thanks!
rekam
December 12,
If you do as you say, and you load a JS file dynamically as mentioned above, any functions in that file should be available from that point forward. There is a bug in IE that you need to be aware of. You need to end the script you are in before calling any functions in the newly loaded script. This is what I mean:

<script>
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'snip.js';
document.getElementsByTagName('head')[0].appendChild(script); 
</script>
<script>
getSomething();
</script>


If you don't use a </script> tag after the appendChild, IE delays the use of the code until it hits an </script> tag. This is not the case in other browsers. So you have to make sure that you close the script before you try and make any calls to the loaded contents. This is true even if you create a function to load the script. The call to the function has to be wrapped inside it's own <script> to work.
Jim Hunter
December 12,
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'snip.js';
document.getElementsByTagName('head')[0].appendChild(script);


does not work in Safari. So using document.write with scripts tags (as it works right now in AW) could be the alternative in these cases.

[QUOTE]
Safari, Konqueror, OmniWeb 4.5+, Internet Explorer on Mac, Opera 7.23-, ICEbrowser, and 4th generation browsers like Internet Explorer 4-, Netscape 4, Opera 6- and iCab do not support this technique
[/QUOTE]

If the script injection has to occur after page load then we need to use only iframes as workarounds, as you know document.write wont help at these scenarios.

Ref:
http://www.howtocreate.co.uk/loadingExternalData.html
Md. Sheriff, Drivestream
December 14,
Good information. Since my pool of users are restricted to the browser I tell them to use (the upside of having a web application that people purchase, you can tell them what to use to access it), I have them currently restricted to IE so I have not run into the above restriction. But for future projects this is good information. Thanks!
Jim Hunter
December 14,
It works for me in Safari 1.3.1; I haven't had a chance to test newer releases.

It also works in Mozilla 1.2.1 (the final release for MacOS 9).

It does NOT work in MSIE 5.2.3 on MacOS X or MSIE 5.0 on MacOS 9.

It does NOT work in iCab (including the latest beta), though I'll report it and see what happens. They're usually pretty responsive -- unless they have chosen not to implement the feature for some reason.
Scott Lawton
December 30,
Hi again!

Jim said that you had to place functions in other script tag for IE. I tested that and that's true, but for Mozilla too. If you have all in the same tag, it will fail (getSomething() does not exists).

By the way, I've got the same problem. I have a HTML file with this :

<html>
<head>
    <script type="text/javascript" src="general.js"></script>
</head>
...


and this inside general.js .

var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'snip.js';
    document.getElementsByTagName('head')[0].appendChild(script); 
    getSomething();


and then that in snip.js :

alert('hello');
function getTruc(){
    alert('something');
}


And the alert of "something" does not appear, because it doesn't find the function. Most probably because the call to this function is considered "in the same script tag" as the code which does the import (which is true, in fact).

The problem is that I don't want a lot of javascript code in the <head> tag. I would like one script tag which insert one file (general.js). And in this file, I would like to do all imports I want. But it seems impossible this way. Or maybe I'm doing something wrong.

Any advice ?
Thanks!
rekam
January 6,
Yeah, of course, the name of the function in snip.js is getSomething() and not getTruc() . Sorry...
rekam
January 6,
I'm trying to use this "on-demand javascript" approach to help load '000s rows of data into the grid.

Previously, I've been working with using ajax calls to fetch JSON structured data and then running eval() on it to produce a javascript object, which in turn is read into a javascript array for the grid. All this works, but the eval() step is slow, especially in IE6. Loading 10,000 rows was taking 40-50 secs. (Why I need 10,000 records is another question, but I just do!)

I've now written the data from the server as straight javascript arrays i.e. myArray = [[a,b,c,],[x,y,z]] etc.. and am delivering it straight into the page as javascript with the "script tag" approach above. Loading times are more than halved, which is great.

The remaining issue seems to be finding a clean way of doing this cross browser (IE & FF for me). The difficulty seems to concern the data load timing i.e. synchronisity: I've seen a solution for IE (article by Jason Levitt - Fixing AJAX: XMLHttpRequest Considered Harmful). This wraps the creation & removal of script tags in a function. Doing this, seems to upset FF. When adding script tags outside of a function, FF seems to work synchronously which is what is wanted in this situation, but as soon as you add script tags in a function, FF executes thru the whole page before the data is finished loading.

I know this is not strictly an AW topic per se, but hopefully this overall approach is a useful one for loading mega data into the grid efficiently.

Any further thoughts on this would be greatly appreciated as always.
Will
Will
January 25,
Got it. Trick is to put code that needs to wait (e.g. code that loads data into grid: obj.setCellText(cells); obj.setRowCount(no_records); obj.setRowIndices(row_index); etc..)
into a seperate function in the main page, and then call that function from the bottom of the newly loaded javascript file after all the data.
Will
January 25,
>>Jim said that you had to place functions in other script tag for IE. I >>tested that and that's true, but for Mozilla too. If you have all in the >>same tag, it will fail (getSomething() does not exists).

any updates on this issue?
howa
February 8,
Good day. Sorry for my english. I had problem with including one javascript file in other javascript file. I try to use your method, but it does not work, then I done crazy thing and it work:

file 1.js with some variables;
file 2.js with functions, which use variables from 1.js;
file a.html where 2.js is included;

I added one string in the beginning of 2.js:
document.write("<script language=JavaScript src=\"1.js\"></script>");

I dont know how but it work
Boom
May 3,
Using this method:
var script = document.createElement('script'); 
script.type = 'text/javascript'; 
script.src = 'snip.js'; 
document.getElementsByTagName('head')[0].appendChild(script);

Is there a way to know when the script has down loaded (to provide a kind of progress indicator when loading several scripts) and know when to start using them. I tried script.onload but that did not work. Any other way this can be done?
John
June 19,
You can have the last like of snip.js call a function.
DT
June 19,
Hej Rekam or anyone else!

How did you manage calling the getSomething() function in the included javascript file?
I have tried but I can not find the way it should work. It has been written that the included javascript must be within a separate <script></script> closures, but is that really so? Can you give me an example how to do it?

I have tried, but can not find a solution at all.
CK
August 6,
Muito bom mesmo este blog. Espero que eu possa aprender mais coisas sempre.
Gaido
September 9,
Does anyone know of a better way of waiting until a script has been loaded into the page?

I'm having problems related to the page not waiting for loads and it causing me some very strange behavior. I am attempting to create a system whereby scripts are not loaded (from .js file) until needed reducing the time taken to download/include scripts as only needed scripts are downloaded.

The following script lives in the head of my page:

<script type="text/javascript">
  var functionCall = "";


  function add(val1, val2){
    alert("Hollow Add");
    document.functionCall = "add(" + val1 + ", " + val2 + ");";
    include('http://192.168.86.195/calculate.js');
    
  }

  function subtract(val1, val2){
      alert("Hollow Subtract");
      document.functionCall = "subtract(" + val1 + ", " + val2 + ");";
      include('http://192.168.86.195/calculate.js');
  }

  function multiply(val1, val2){
      alert("Hollow Multiply");
      document.functionCall = "multiply(" + val1 + ", " + val2 + ");";
      include('http://192.168.86.195/calculate.js');
  }

  function divide(val1, val2){
      alert("Hollow Divide");
      document.functionCall = "divide(" + val1 + ", " + val2 + ");";
      include('http://192.168.86.195/calculate.js');
  }

  function addDivide(val1, val2){
        alert("Hollow Add & Divide");
        document.functionCall = "addDivide(" + val1 + ", " + val2 + ");";
        include('http://192.168.86.195/advancedLib.js');
  }

  function include(src){
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
    document.getElementsByTagName('head')[0].appendChild(script);
  }
</script>


Note that the last lines of each js file to be included performs an eval of whatever value is in document.functionCall

This will work depending on how quickly calls to functions are made. If it is possible to block/wait until the .js file is downloaded and included then I will have no more problems (including the whole thing about ending the <script> before calling the new functions which works fine for me in IE and Firefox)

Also if the waiting were in fact to work I could change the code to be like:
function add(val1, val2){
      alert("Hollow Add");
      include('http://192.168.86.195/calculate.js');
      add(val1, val2);
  }
  
  ...
  
  function include(src){
      var script = document.createElement('script');
      script.type = 'text/javascript';
      script.src = src;
      document.getElementsByTagName('head')[0].appendChild(script);
      *** BLOCKING CODE ***
  }


Which would be much nicer and would not require the eval scripting to be added to any .js file to be included.
Trevor
September 21,
Just hoping that someone will have some idea about how to resolve me problem (detailed above) and post a reply.
Trevor
September 24,
hai iamnew to use thes ewidget components in java script plz help me it with some examples
as iam in to the project from tomorrow

dilep
September 25,
Well dilep, perhaps you should post some more specific questions. Maybe they'll be addressed. But judging by peoples responses to my above queries I must admit I don't like your chances. :(
Trevor
September 28,
Hey Trevor,

What are the possibilities of using xmlhttp request to include the function? that way you can control the order and wait. The request could return the function in a string and you simply append it. it becomes a question of trips to the server versus loading the js initially (although - it looks like the way you are doing it might also require multiple trips).
not sure how you would know exactly when the include loaded the way you are doing it.
Joel
September 28,
Trevor,

One question. Shouldn't you track whether the code has already been added to the page? If it has, then you don't need to get it.

Joel
September 28,
Well, an example of the way it works is this:
1. call the add function
2. The script has not loaded so the hollow version runs (which downloads the actual version, then runs it with what looks like a recursive call but does in fact call the new version)

then on subsequent attempts:

1. call the add function
2. The script has loaded so THE NEW version of the routine is executed (don't ask me why but it does, if the page contains a subroutine and it includes a js file containing a subroutine with the same definition as the one on the page the included subroutine is run)
Trevor
September 28,
What are the possibilities of using xmlhttp request to include the function?

Possibilities are not good as I have never used xmlhttp requests and have thus far been unable to determine how I could implement such a method.

Any help with this would be very much appreciated.
Trevor
September 28,
It is possible to do a xmlhttp request to include the function:

1. Get the script-code in a string with a xmlhttp request.
2. Do this:

var script = document.createElement("script");
script.lang = 'javascript';
script.text = string;
document.appendChild(script);

I have used this method 'live' (with use of AW) and it works.
Eric Aarts
September 29,
yes - exactly what I had in mind. you could use the AW request or simply code one yourself. Trevor - let me know if you need an example - I'll dig it up. But if you search for XMLHTTP it is pretty easy to implement.
Joel
September 29,
Here is some sample code for AW.HTTP.Request -

var req = new AW.HTTP.Request;
req.setURL('<url>');
req.response = function(text) {
    alert(text); // do something with response here
};
req.request(); // send the request (async by default)



http://www.activewidgets.com/aw.http.request/request.html
Alex (ActiveWidgets)
September 29,
Hi All,

I have a problem, I am using a dropdown and on select of a particular option in the dropdown i need to call another script(js method) to include another row in the table.
can anyone help me with this

Thanks
SGR
October 23,
Here is one better: a script that tests whether or not a library has been loaded. I have an issue in that my Ajax content often requires libraries that have already been loaded in the main page. Reloading the libraries will reinitialize all the arrays in the library source. Therefore I need to check whether the library has been loaded before I re-request it.

Of course, this specific script may be re-required by embedded Ajax blocks but that is not a concern, as it only used DOM-defined global variables.

<script language="javascript">

function load_script(src)
{
var document_scripts = document.getElementsByTagName("script");

for (document_scripts_index = 0; document_scripts_index < document_scripts.length; ++document_scripts_index)
{
var document_script = document_scripts[document_scripts_index];
if (document_script.src == src) return false;
}

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
document.getElementsByTagName('head')[0].appendChild(script);
}
</script>
Dave Edelhart
January 24,
Actually, not only do I prevent redundant loading at the client, I do a first pass at the server. The full codebase is at

http://www.wonderlandlabs.com/modules/wiwimod/index.php?page=TheJavaScriptLibaryParadox&back=AjaxNotes
Dave Edelhart
January 24,
Interesting discussions.

I can't believe I'm only now seeing this article. I released the first version of AJILE, my cross-browser solution to this problem, back in 2003!!! For years I searched the web looking for people interested in a solution; it seemed at the time that no one recognized the problem or the need for a solution, well AJAX has changed that ;-)!

Check out Ajile at http://ajile.iskitz.com/.

Along with importing scripts Ajile also lets you to create namespaces, hide your code, and have your web pages automatically import scripts specifically by page or shared across all pages in your entire site!
Michael Lee
July 28,

This topic is archived.

See also:


Back to support forum