Jump to content

Dynamically Loading Code


Wylbur
 Share

Recommended Posts

Hi all;I'm trying to dynamically load javascript from a file with a click handler.The code is for a class function.I'm instantiating an instance of the class from the click handler.It doesn't work the first time I call the "constructor" function,but it does work the second time.If I put in a call to the "alert" method, it works the first time (and every time).From this, it would be logical to conclude that the code being loadedisn't being given time enough to load and be implanted within the DOMstructure for the page before it's called.How can I get the click handler to wait for the code to get established?What follows is the code for the method that inserts the tag to loadthe java script:

function	 load_js_code_from_file (js_code_file){   var form_ref = document.getElementById ("theForm1");   var new_js_node = document.createElement ("script");   new_js_node.setAttribute ("language", "javascript");   new_js_node.setAttribute ("src", js_code_file);   form_ref.appendChild (new_js_node);	//  alert ("js_code_file::" + js_code_file + "::");   return true;}

This is the click handler:

   load_js_code_from_file ("file:///C:\\Javascript\\Sum_code.js");	//  alert ("js code loaded");   var sumthin = new x_class ();

THANKS!

Link to comment
Share on other sites

Why is the new script tag being appended to a form instead of the head? You should be able to add alerts to the file you're loading to see the chain of events, but if you add the script to the head then it should be processed before the rest of the code executes.

Link to comment
Share on other sites

Hi Guy;

Why is the new script tag being appended to a form instead of the head?
That's a good question, and one that I have asked myself.Since I made the initial post, I tried appending the script node tothe children of the head tag, and that didn't work either - I got thesame behavior as before (it fails on the first call, but works finewith every call thereafter).I then tried the "insertBefore" method to make it the first script nodein the head tag, but I got the same result.This is the current state of the insertion method, with what had beentried before commented out:
function	 load_js_code_from_file (js_code_file){  //   var parent_ref  = document.getElementById ("theForm1");   var parent_ref = document.getElementsByTagName("head")[0];    var new_js_node = document.createElement ("script");   new_js_node.setAttribute ("language", "javascript");   new_js_node.setAttribute ("src", js_code_file);  // parent_ref appendChild (new_js_node);   if (parent_ref firstChild)	   parent_ref.insertBefore (new_js_node, parent_ref.firstChild);   else	   alert ("parent_ref.firstChild is NULL!");	//  alert ("js_code_file::" + js_code_file + "::");	   js_code_is_loaded = true;}

I'm getting the same behavior from both the appendChild methodand the insertBefore method: It doesn't work the first time(on the initial page request), but it does every time afterwards,unless I put in a call to the alert method (and it works every timewhen I do that).I'll tell you something else that's odd. When I try to catchthe thrown exception, it doesn't work at all:

   var sumthin;   load_js_code_from_file ("file:///C:\\Javascript\\Sum_code.js");	//  alert ("js code loaded");   try   {   sumthin = new x_class ();   }   catch   {   alert ("Somethin went wrong!");   }

You should be able to add alerts to the file you're loading to see the chain of events, but if you add the script to the head then it should be processed before the rest of the code executes.
As I mentioned in my initial post: When I put in calls to the alert method,it works every time (the initial page request inclusive). I'm guessing thatthe alert method gives something the time it needs to get done whateverit is that it needs to get done before the object is instantiated.THANK YOU for the response!!!
Link to comment
Share on other sites

Your catch statement should look like this: catch(e)It sounds like you've put yourself in a race condition, and the first time up, the code is executing faster than the file can be read. (The alert gives the src time to load.) If it's possible consider loading the file when the page first loads. Then it'll be there when the click event fires.Alternatively, try wrapping your try-catch structure in a while loop. Keep executing the loop until the thing works. (Obviously, you'll need to test this carefully. For all I know, something else is the issue and you'll end up in an infinite loop.)

Link to comment
Share on other sites

Your catch statement should look like this: catch(e)
Ah - thank you for setting me straight on that.
It sounds like you've put yourself in a race condition, and the first time up, the code is executing faster than the file can be read. (The alert gives the src time to load.)
That's what I was thinking.
If it's possible consider loading the file when the page first loads. Then it'll be there when the click event fires.
That would not be possible under the set of circumstances that I'm operating with.
Alternatively, try wrapping your try-catch structure in a while loop. Keep executing the loop until the thing works. (Obviously, you'll need to test this carefully. For all I know, something else is the issue and you'll end up in an infinite loop.)
I was thinking the same thing (but it wasn't working right as I made a mistake with the catch partbefore you set me straight).I had to fiddle with it a bit before I got the click handler to execute without blowing up.I have now reached the point to where I am getting a legitimate error message - again - on theinitial page request (then it works fine after that). I've set a counter variable to zero, thenincremented it with a for-loop on the try-catch structure.It loops through 0x0008fff0 iterations before giving an error message (and takes a while in doing it).The click handler now looks like this:
   var sumthin = null;   var ld_cntr = 0;   var stop_val = 0x0008fff0;    load_js_code_from_file ("file:///C:\\Javascript\\Sum_code.js");//alert ("loaded");   for (; ld_cntr < stop_val; ld_cntr++)   {   try   {	   sumthin = new x_class ();	   ld_cntr = stop_val;   }   catch (e)   {   }   }   if (ld_cntr == stop_val)	   alert ("error");

As before, if I uncomment the alert method at the first of the handler,it works just fine. If I don't, then it issues the alert on the conditional("if (ld_cntr == stop_val)").THANK YOU for the response!!!

Link to comment
Share on other sites

If it works, great. I suddenly realized (headsmack) that it would probably be more efficient to put the thing on a recursive timer that executes every 50 milliseconds or so.

Edited by Deirdre's Dad
Link to comment
Share on other sites

Another way to do it is to send an ajax request for the Javascript code and put it directly in the script element, then use a callback to execute whatever comes next. That's how this ExtJS extension does it:

Ext.ux.OnDemandLoadByAjax = function(){	loadComponent = function(component, callback, scope, mask){		handleSuccess = function(response, options) {			if ((typeof mask) != 'undefined' && (typeof mask.hide) == 'function')			  mask.hide();			var type = component.substring(component.lastIndexOf('.'));			var head = document.getElementsByTagName("head")[0];			var js = document.createElement('script');			js.setAttribute("type", "text/javascript");			js.text = response.responseText;			if (!document.all) {				js.innerHTML = response.responseText;			}			head.appendChild(js);			if(typeof callback == "function"){				if(document.all) {					callback.call(scope);				} else {					callback.createDelegate(scope).defer(50);				}			};		};		handleFailure = function(response, options) {			if ((typeof mask) != 'undefined' && (typeof mask.hide) == 'function')			  mask.hide();			alert('Dynamic load script: [' + component + '] failed!');		};		Ext.Ajax.request({			url: component,			method: 'GET',			success: handleSuccess,			failure: handleFailure,			disableCaching : true		});	};	return {		load: function(components, callback, scope, mask){			Ext.each(components, function(component){				loadComponent(component, callback, scope, mask);			});		}	};}();

Even there though it will defer execution of the callback for 50 milliseconds for certain browsers.

Link to comment
Share on other sites

If it works, great.
Not-so-great if it doesn't work on the first go-round, or if I need to put in a call tothe "alert" method in order to get it to work every time.
I suddenly realized (headsmack) that it would probably be more efficient to put the thing on a recursive timer that executes every 50 milliseconds or so.
That doesn't really help me, as the "setTimeout" method works asynchronously, so the objectthat needs to be instantiated from the class defined within the dynamically loaded codeis still null when it gets used later in the code. I cannot utilize the object from withinmethods called later in the execution sequence from the timed method set from the"setTimeout" method (so that isn't a viable option in case you were thinking along those lines). ... unless I'm being dense (again) and not thinking of something that most smart people wouldthink of.Otherwise, I'm still in want of a "wait" method that will halt execution until the objectis (actually) instantiated.THANK YOU for the response!!! ... and say "HI" to Deirdre for me. Edited by Wylbur
Link to comment
Share on other sites

Hi Guy;

Another way to do it is to send an ajax request for the Javascript code and put it directly in the script element, then use a callback to execute whatever comes next. That's how this ExtJS extension does it:
Ext.ux.OnDemandLoadByAjax = function(){	loadComponent = function(component, callback, scope, mask){		handleSuccess = function(response, options) {			if ((typeof mask) != 'undefined' && (typeof mask.hide) == 'function')			  mask.hide();			var type = component.substring(component.lastIndexOf('.'));			var head = document.getElementsByTagName("head")[0];			var js = document.createElement('script');			js.setAttribute("type", "text/javascript");			js.text = response.responseText;			if (!document.all) {				js.innerHTML = response.responseText;			}			head.appendChild(js);			if(typeof callback == "function"){				if(document.all) {					callback.call(scope);				} else {					callback.createDelegate(scope).defer(50);				}			};		};		handleFailure = function(response, options) {			if ((typeof mask) != 'undefined' && (typeof mask.hide) == 'function')			  mask.hide();			alert('Dynamic load script: [' + component + '] failed!');		};		Ext.Ajax.request({			url: component,			method: 'GET',			success: handleSuccess,			failure: handleFailure,			disableCaching : true		});	};	return {		load: function(components, callback, scope, mask){			Ext.each(components, function(component){				loadComponent(component, callback, scope, mask);			});		}	};}();

Even there though it will defer execution of the callback for 50 milliseconds for certain browsers.

This could very possibly work, but, unless I'm mistaken, I'd need something in the wayof a server to send the response. As things stand now, there is no server involvement.THANK YOU for the response!!!
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...