Trigger $document.ready (so AJAX code I can't modify is executed) - javascript

My requirements are the following:
I've got a rich webpage that at a certain moment loads a bunch of HTML in a div, via AJAX.
The HTML I retrieve does have javascript (<script>...</script>)
The retrieved javascript contains $('document').ready( ... ) parts
I can not modify the retrieved javascript; it comes from an external lib
I've got a javascript function that is called when the AJAX is loaded. I'm trying to "trick it" into executing by doing:
function AjaxLoaded() {
$('document').trigger('ready');
}
That doesn't cut it, I'm afraid.
I've seen several responses on Stack Overflow that "evade" this question by changing the code that is returned on the AJAX (make it a function and call it after loading, or just remove the $(document).ready()). I need to stress out that I can't change the retrieved code on this case.

Afer some research i created a way to get it to work.
here is my test that shows it working: http://www.antiyes.com/test/test2.php
here is the relevant code:
<script>
// easy copy of an array
Array.prototype.copy = function() {
return [].concat(this);
};
// this function is added to jQuery, it allows access to the readylist
// it works for jQuery 1.3.2, it might break on future versions
$.getReadyList = function() {
if(this.readyList != null)
this.myreadylist = this.readyList.copy();
return this.myreadylist;
};
$(document).ready(function() {
alert("blah");
});
</script>
<script>
// this should be added last so it gets all the ready event
$(document).ready(function() {
readylist = $.getReadyList();
});
</script>
then in the body I have:
<input type="button" onclick="$(readylist).each(function(){this();});" value="trigger ready" />
basically what i did was add a function to jQuery that copies the readyList before it's cleared out, then it will be available to be used by you.
it looks like the code below doesnt work:
function AjaxLoaded() {
$(document).trigger('ready');
}
drop the quotes around document.

Since the jQuery readyList is not exposed as of version 1.4 (discussed here) the nice solutions above are broken.
A way around this is by creating your own readyList, through overriding the original jQuery-ready method. This needs to be done before other scripts that use the original ready method are loaded. Otherwise just the same code as John/Kikito:
// Overrides jQuery-ready and makes it triggerable with $.triggerReady
// This script needs to be included before other scripts using the jQuery-ready.
// Tested with jQuery 1.7
(function(){
var readyList = [];
// Store a reference to the original ready method.
var originalReadyMethod = jQuery.fn.ready;
// Override jQuery.fn.ready
jQuery.fn.ready = function(){
if(arguments.length && arguments.length > 0 && typeof arguments[0] === 'function') {
readyList.push(arguments[0]);
}
// Execute the original method.
originalReadyMethod.apply( this, arguments );
};
// Used to trigger all ready events
$.triggerReady = function() {
$(readyList).each(function(){this();});
};
})();
I'm not sure whether it is advisable to override the ready method. Feel free to advise me on that. I have not yet found any side effects myself though.

Just in case anyone needs it, I refined John's solution a bit so it could be used directly as an included javascript file.
// jquery_trigger_ready.js
// this function is added to jQuery, it allows access to the readylist
// it works for jQuery 1.3.2, it might break on future versions
$.getReadyList = function() {
if(this.readyList != null) { this.myreadylist = [].concat(this.readyList); }
return this.myreadylist;
};
$(document).ready(function() {
readylist = $.getReadyList();
});
$.triggerReady = function() {
$(readylist).each(function(){this();});
}
Including this file after including jquery allows for triggering ready by invoking $.triggerReady(). Example:
<html>
<head>
<title>trigger ready event</title>
<script src="test2_files/jquery-1.js" type="text/javascript"></script>
<script src="jquery_trigger_ready.js" type="text/javascript"></script>
</head>
<body>
<input onclick="$.triggerReady();" value="trigger ready" type="button">
<script type="text/javascript">
$(document).ready(function(){
alert("blah");
});
</script>
</body>
</html>
By the way, I wanted to make it $(document).triggerReady(). If anyone is willing to share some advice on that, ill be appreciated.

We had the same problem and solved it another way.
Instead of
$(document).ready(function () {
$('.specialClass').click(....
We used :
$(document).bind('ready', function(event) {
$('.specialClass', event.target).click(..
jQuery will trigger a "ready" event on the document as usual. When we load the content of a new div via ajax, we can write:
loadedDiv.trigger('ready')
And have all the initialization performed only on the div, obtaining what expected.

Simone Gianni's Answer I think is the most elegant and clean.
and you can even simplify it to become even more easy to use:
jQuery.fn.loadExtended = function(url,completeCallback){
return this.load(url,function(responseText, textStatus, XMLHttpRequest) {
if (completeCallback !== undefined && completeCallback !== null) {
completeCallback(responseText, textStatus, XMLHttpRequest);
}
$(this).trigger("ready");
});
};
So, now instead of using:
$(".container").load(url,function(responseText, textStatus, XMLHttpRequest) {
$(this).trigger("ready");
});
you can just use:
$(".container").loadExtended("tag_cloud.html");
or:
$(".container").loadExtended("tag_cloud.html",function(){
alert('callback function')
});
This has the advantage of only applying the trigger on the div that's being updated.

If your new loaded HTML contain <script> elements and you try insert it into main HTML with pure JS (element.innerHTML = newHTML), then $(document).ready handlers at newHTML and wrapped functions like (function() { /* some functions */ })(); - will not execute because JQuery unbind 'ready' event after first triggering and you can not trigger it repeatly. PS. But you can use $.holdReady(true) and trigger when need.
So, try insert code with jquery method, $(element).html(newHTML). This solved similar problem for me, seems jquery handle js before inserting. Using this method you also will not see the <script> elements among DOM nodes (at browser's Elements Inspector for ex.)

Related

Is it possible to pre-register handlers before jQuery is loaded?

The situation where jQuery is loaded late on the page but javascript that relies on jQuery being available is loaded before jQuery is a pretty common scenario, especially if you follow the practice of putting your scripts closer to </body>.
So basically I want to go from this:
<script>
someFunctionThatUsesLateJQuery(){ [code that relies on jQuery] }
</script>
...
<script src="jquery.js"></script>
<script>
$(function(){
someFunctionThatUsesLateJQuery();
});
</script>
To something like this:
<script>
_$.ready(function(){ [code that relies on jQuery] });
</script>
...
<script src="jquery.js"></script>
Much like asynchronous stats tracking (รก la Google Analytics), is there anything out there that allows you to register javascript function calls to be executed once jQuery is loaded without getting the dreaded $ is undefined error?
I mean for this to happen without registering and deregistering timeouts/intervals.
Has there ever been/is there the possibility of adding some sort of pre-registration variable to jQuery that it recognises and handles once it's loaded?
Use case:
It's worth noting that the specific use-case I've got is a drop-in JS widget, where I want some DOM manipulation to happen at the scene of the <script> placement, which therefore has the very real possibility of appearing before jQuery has loaded in the case of jQuery loading happening near </body>.
I then don't want to burden the user further by requiring them to register a specific function call at the correct point in code execution (which will be dependent on their implementation)... I want it to "just work"
As suggested here by rich.okelly you could try this:
(function() {
var runMyCode = function($) {
// jquery-dependent code here
$("#foo").data('bar', true);
};
var timer = function() {
if (window.jQuery && window.jQuery.ui) {
runMyCode(window.jQuery);
} else {
window.setTimeout(timer, 100);
}
};
timer();
})();
I also found a more complex solution, but I personally prefer the above solution over this solution.
Update without timeout:
<script>
var runMyCode = function($) {
// jquery-dependent code here
$("#foo").data('bar', true);
};
</script>
...
<script src="jquery.js"></script>
<script>
$(function(){
runMyCode(window.jQuery);
});
</script>
You could try to use common and popular solution when all your function calls moved to data-attributes. Then, when jQuery is loaded, you go throw all the DOM elements with such attributes and run this functions.
I.e. instead of function call you add data-type='load' data-function='YourNamespace.yourFunctionName' and after window.load event you select all the elements by $('[data-type="load"]'), iterates them, and perform function calls.
UPD: Guess, async function queuing pattern could be usefull to read about:
What's the name of Google Analytics async design pattern and where is it used?
If you inject the jQuery script include, then you can listen for the onload event.
function loadJS(url, onloadCallback, elId){
//Inject script include into HEAD
var scriptEl = document.createElement('script');
scriptEl.type = 'text/javascript';
scriptEl.src = url;
if(elId)scriptEl.id = elId;
document.getElementsByTagName('head')[0].appendChild(scriptEl);
if(onloadCallback){
scriptEl.onload = scriptEl.onreadystatechange = function(){
if(!scriptEl.readyState || (scriptEl.readyState === 'complete' || scriptEl.readyState === 'loaded')){
onloadCallback();
scriptEl.onload = scriptEl.onreadystatechange = null;
}
}
}
}
loadJS("http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js", function(){
console.log( window.$ );
});
Perhaps I don't understand the use case fully, but RequireJS sounds like it might be a good option for you:
https://github.com/requirejs/example-jquery-shim
define(["jquery", "jquery.alpha", "jquery.beta"], function($) {
//the jquery.alpha.js and jquery.beta.js plugins have been loaded.
$(function() {
$('body').alpha().beta();
});
});

execute function after complete page load [duplicate]

This question already has answers here:
How to make JavaScript execute after page load?
(25 answers)
Closed 1 year ago.
I am using following code to execute some statements after page load.
<script type="text/javascript">
window.onload = function () {
newInvite();
document.ag.src="b.jpg";
}
</script>
But this code does not work properly. The function is called even if some images or elements are loading. What I want is to call the function the the page is loaded completely.
this may work for you :
document.addEventListener('DOMContentLoaded', function() {
// your code here
}, false);
or
if your comfort with jquery,
$(document).ready(function(){
// your code
});
$(document).ready() fires on DOMContentLoaded, but this event is not being fired consistently among browsers. This is why jQuery will most probably implement some heavy workarounds to support all the browsers. And this will make it very difficult to "exactly" simulate the behavior using plain Javascript (but not impossible of course).
as Jeffrey Sweeney and J Torres suggested, i think its better to have a setTimeout function, before firing the function like below :
setTimeout(function(){
//your code here
}, 3000);
JavaScript
document.addEventListener('readystatechange', event => {
// When HTML/DOM elements are ready:
if (event.target.readyState === "interactive") { //does same as: ..addEventListener("DOMContentLoaded"..
alert("hi 1");
}
// When window loaded ( external resources are loaded too- `css`,`src`, etc...)
if (event.target.readyState === "complete") {
alert("hi 2");
}
});
same for jQuery:
$(document).ready(function() { //same as: $(function() {
alert("hi 1");
});
$(window).load(function() {
alert("hi 2");
});
NOTE: - Don't use the below markup ( because it overwrites other same-kind declarations ) :
document.onreadystatechange = ...
I'm little bit confuse that what you means by page load completed, "DOM Load" or "Content Load" as well? In a html page load can fire event after two type event.
DOM load: Which ensure the entire DOM tree loaded start to end. But not ensure load the reference content. Suppose you added images by the img tags, so this event ensure that all the img loaded but no the images properly loaded or not. To get this event you should write following way:
document.addEventListener('DOMContentLoaded', function() {
// your code here
}, false);
Or using jQuery:
$(document).ready(function(){
// your code
});
After DOM and Content Load: Which indicate the the DOM and Content load as well. It will ensure not only img tag it will ensure also all images or other relative content loaded. To get this event you should write following way:
window.addEventListener('load', function() {...})
Or using jQuery:
$(window).on('load', function() {
console.log('All assets are loaded')
})
If you can use jQuery, look at load. You could then set your function to run after your element finishes loading.
For example, consider a page with a simple image:
<img src="book.png" alt="Book" id="book" />
The event handler can be bound to the image:
$('#book').load(function() {
// Handler for .load() called.
});
If you need all elements on the current window to load, you can use
$(window).load(function () {
// run code
});
If you cannot use jQuery, the plain Javascript code is essentially the same amount of (if not less) code:
window.onload = function() {
// run code
};
If you wanna call a js function in your html page use onload event. The onload event occurs when the user agent finishes loading a window or all frames within a FRAMESET. This attribute may be used with BODY and FRAMESET elements.
<body onload="callFunction();">
....
</body>
You're best bet as far as I know is to use
window.addEventListener('load', function() {
console.log('All assets loaded')
});
The #1 answer of using the DOMContentLoaded event is a step backwards since the DOM will load before all assets load.
Other answers recommend setTimeout which I would strongly oppose since it is completely subjective to the client's device performance and network connection speed. If someone is on a slow network and/or has a slow cpu, a page could take several to dozens of seconds to load, thus you could not predict how much time setTimeout will need.
As for readystatechange, it fires whenever readyState changes which according to MDN will still be before the load event.
Complete
The state indicates that the load event is about to fire.
This way you can handle the both cases - if the page is already loaded or not:
document.onreadystatechange = function(){
if (document.readyState === "complete") {
myFunction();
}
else {
window.onload = function () {
myFunction();
};
};
}
you can try like this without using jquery
window.addEventListener("load", afterLoaded,false);
function afterLoaded(){
alert("after load")
}
Alternatively you can try below.
$(window).bind("load", function() {
// code here });
This works in all the case. This will trigger only when the entire page is loaded.
window.onload = () => {
// run in onload
setTimeout(() => {
// onload finished.
// and execute some code here like stat performance.
}, 10)
}
If you're already using jQuery, you could try this:
$(window).bind("load", function() {
// code here
});
I can tell you that the best answer I found is to put a "driver" script just after the </body> command. It is the easiest and, probably, more universal than some of the solutions, above.
The plan: On my page is a table. I write the page with the table out to the browser, then sort it with JS. The user can resort it by clicking column headers.
After the table is ended a </tbody> command, and the body is ended, I use the following line to invoke the sorting JS to sort the table by column 3. I got the sorting script off of the web so it is not reproduced here. For at least the next year, you can see this in operation, including the JS, at static29.ILikeTheInternet.com. Click "here" at the bottom of the page. That will bring up another page with the table and scripts. You can see it put up the data then quickly sort it. I need to speed it up a little but the basics are there now.
</tbody></body><script type='text/javascript'>sortNum(3);</script></html>
MakerMikey
I tend to use the following pattern to check for the document to complete loading. The function returns a Promise (if you need to support IE, include the polyfill) that resolves once the document completes loading. It uses setInterval underneath because a similar implementation with setTimeout could result in a very deep stack.
function getDocReadyPromise()
{
function promiseDocReady(resolve)
{
function checkDocReady()
{
if (document.readyState === "complete")
{
clearInterval(intervalDocReady);
resolve();
}
}
var intervalDocReady = setInterval(checkDocReady, 10);
}
return new Promise(promiseDocReady);
}
Of course, if you don't have to support IE:
const getDocReadyPromise = () =>
{
const promiseDocReady = (resolve) =>
{
const checkDocReady = () =>
((document.readyState === "complete") && (clearInterval(intervalDocReady) || resolve()));
let intervalDocReady = setInterval(checkDocReady, 10);
}
return new Promise(promiseDocReady);
}
With that function, you can do the following:
getDocReadyPromise().then(whatIveBeenWaitingToDo);
call a function after complete page load set time out
setTimeout(function() {
var val = $('.GridStyle tr:nth-child(2) td:nth-child(4)').text();
for(var i, j = 0; i = ddl2.options[j]; j++) {
if(i.text == val) {
ddl2.selectedIndex = i.index;
break;
}
}
}, 1000);
Try this jQuery:
$(function() {
// Handler for .ready() called.
});
Put your script after the completion of body tag...it works...

Handling code which relies on jQuery before jQuery is loaded

I'd like to follow the general guideline of putting all JavaScript at the very bottom of the page, to speed up loading time and also to take care of some pesky issues with conflicting jQuery versions in a web app (Django).
However, every so often I have some code, code which depends on jQuery, but which must be further up on the page (basically the code can't be moved to the bottom).
I'm wondering if there's an easy way to code this so that even though jQuery is not yet defined the code works when jQuery is defined.
The following seems, I have to say, like overkill but I don't know of another way to do it:
function run_my_code($) {
// jquery-dependent code here
$("#foo").data('bar', true);
}
var t = null;
function jquery_ready() {
if (window.jQuery && window.jQuery.ui) {
run_my_code(window.jQuery);
} else {
t = window.setTimeout(jquery_ready, 100);
}
}
t = window.setTimeout(jquery_ready, 100);
Actually, I might need to use code more than once in a page, code that doesn't know about other code, so even this probably won't work unless I rename each jquery_ready to something like jquery_ready_guid, jquery_ready_otherguid and so on.
Clarification
Just so this is clear, I am putting the include to JavaScript (<script type="text/javascript" src="jquery.min.js" />) at the very bottom of the page, just before the </body>. So I can't use the $.
Simple use pure javascript version of $(document).ready();:
document.addEventListener("DOMContentLoaded", function(event) {
//you can use jQuery there
});
Your way is the only way that I know of, though I would ensure that the scoping is a little tighter:
(function() {
var runMyCode = function($) {
// jquery-dependent code here
$("#foo").data('bar', true);
};
var timer = function() {
if (window.jQuery && window.jQuery.ui) {
runMyCode(window.jQuery);
} else {
window.setTimeout(timer, 100);
}
};
timer();
})();
Update
Here's a little deferred loader I cobbled together:
var Namespace = Namespace || { };
Namespace.Deferred = function () {
var functions = [];
var timer = function() {
if (window.jQuery && window.jQuery.ui) {
while (functions.length) {
functions.shift()(window.jQuery);
}
} else {
window.setTimeout(timer, 250);
}
};
timer();
return {
execute: function(onJQueryReady) {
if (window.jQuery && window.jQuery.ui) {
onJQueryReady(window.jQuery);
} else {
functions.push(onJQueryReady);
}
}
};
}();
Which would then be useable like so:
Namespace.Deferred.execute(runMyCode);
The best way I have found is to write the code in a function and call the function after jquery is loaded:
function RunAfterjQ(){
// Codes that uses jQuery
}
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
RunAfterjQ();
</script>
Update: For master pages, you can define an array to push functions in the head of the master page:
var afterJQ = [];
then at the bottom of master page run all the functions pushed in to this array:
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
for(var i = 0; i < afterJQ.length; i++) afterJQ[i]();
</script>
Everywhere that you need to use javascript that relies on jQuery and is before jQuery is defined just push it in to this array:
afterJQ.push( function() {
// this code will execute after jQuery is loaded.
});
Here is a way to write injected code that will be run only after jQuery loads (whether synchronously or asynchronously).
<script>
if ( ! window.deferAfterjQueryLoaded ) {
window.deferAfterjQueryLoaded = [];
Object.defineProperty(window, "$", {
set: function(value) {
window.setTimeout(function() {
$.each(window.deferAfterjQueryLoaded, function(index, fn) {
fn();
});
}, 0);
Object.defineProperty(window, "$", { value: value });
},
configurable: true
});
}
window.deferAfterjQueryLoaded.push(function() {
//... some code that needs to be run
});
</script>
What this does is:
Defines deferAfterjQueryLoaded lazily, so you don't need to inject that into head.
Defines a setter for window.$. When jQuery loads, one of the last things it does is assign to the global $ variable. This allows you to trigger a function when that happens.
Schedules the deferred functions to run as soon as possible after the jQuery script finishes (setTimeout(..., 0);).
Has the setter remove itself.
For complete cleanliness you could have the scheduled function remove deferAfterjQueryLoaded as well.
How about:
<script>
window.deferAfterjQueryLoaded = [];
window.deferAfterjQueryLoaded.push(function() {
//... some code that needs to be run
});
// ... further down in the page
window.deferAfterjQueryLoaded.push(function() {
//... some other code to run
});
</script>
<script src="jquery.js" />
<script>
$.each(window.deferAfterjQueryLoaded, function(index, fn) {
fn();
});
</script>
This works because every script here is completely blocking. Meaning the creation of the deferAfterjQueryLoaded array and all functions being created and pushed to that array occur first. Then jQuery completely loads. Then you iterate through that array and execute each function. This works if the scripts are in separate files as well just the same way.
If you ALSO want DOMReady to fire you can nest a $(function() {}) inside of one of your deferAfterjQueryLoaded functions like such:
window.deferAfterjQueryLoaded.push(function() {
$(function() {
console.log('jquery loaded and the DOM is ready');
});
console.log('jquery loaded');
});
Ultimately, you should really refactor your code so everything is actually down at the bottom, and have a system conducive to that model. It is much easier to understand everything occurring and more performant (especially if you have separate scripts).
I have this same problem, but with a ton of files, I use headjs to manage the loading, it's only 2kb so there isn't really a problem, for me anyway, of putting in the header. Your code then becomes,
head.ready(function(){
$...
});
and at the bottom of the page,
head.js('/jquery.min.js');
You should be able to do this on a document ready event.
function jQueryGodot(code)
{
if (window.jQuery)
{
code(window.jQuery);
}
else
{
if (!window.$)
{
window.$ = { codes: [] };
window.watch('$', function(p, defered, jQuery) {
jQuery.each(defered.codes, function(i, code) {
code(jQuery);
});
return jQuery;
});
}
window.$.codes.push(code);
}
}
jQueryGodot(function($) {
$('div').html('Will always work!');
})
Working example on JSFiddle.
Code passed to jQueryGodot function will always be executed no matter if it is called before or after jQuery is loaded.
The solution relies on Object.watch which requires this polyfill (660 bytes minified) in most of the browsers: https://gist.github.com/adriengibrat/b0ee333dc1b058a22b66
You can defer all calls like jQuery(function(){...}) without the loop of a setTimeout: https://jsfiddle.net/rL1f451q/3/
It is collecting every jQuery(...) call into an array until jQuery is not defined, then the second code executes them when jQuery is available.
Put this in the head or the beginning of the body:
<!-- jQuery defer code body: deferring jQuery calls until jQuery is loaded -->
<script>
window.jQueryQ = window.jQueryQ || [];
window.$ = window.jQuery = function(){
window.jQueryQ.push(arguments);
}
</script>
<!-- end: jQuery defer code body -->
And this at the very end of the body, after the jQuery script:
<!-- jQuery deferring code footer: add this to the end of body and after the jQuery code -->
<script>
jQuery(function(){
jQuery.each(window.jQueryQ||[],function(i,a){
// to understand why setTimeout 0 is useful, see: https://www.youtube.com/watch?v=8aGhZQkoFbQ, tldr: having a lot of calls wont freeze the website
setTimeout(function(){
jQuery.apply(this,a);
},0);
});
});
</script>
<!-- end: jQuery deferring code footer -->
I've wrote simple js code for handle such cases: https://github.com/Yorkii/wait-for
Then you can use it like this
waitFor('jQuery', function () {
//jQuery is loaded
jQuery('body').addClass('done');
});
You can even wait for multiple libraries
waitFor(['jQuery', 'MyAppClass'], function () {
//Both libs are loaded
});
I'm posting my answer using a JavaScript promise. It works, it is simple and reusable.
The advantage is, that the code get's executed as soon as jQuery is loaded, no matter how early or late on the page.
But, I'm by far not as experienced like some other people in this thread. So I'd love my answer to be peer reviewed. I'd like to know if it really is a valid solution and what the downsides are.
Write an objectExists function with a promise as high up in the code as you want.
function jqueryExists() {
return new Promise(function (resolve, reject) {
(function waitForJquery() {
if (jQuery) return resolve();
setTimeout(waitForJquery, 30);
})();
});
}
Then add your function which depends on jQuery. As far as I understand, it won't block any other script from execution, and the page will load just fine even if jQuery is loaded much later.
jqueryExists().then(function(){
// Write your function here
}).catch(function(){
console.log('jQuery couldn\'t be loaded');
})
jQuery can now be loaded after this code, and the function will execute as soon as jQuery is available.

How to unload a javascript from an html?

How can I unload a JavaScript resource with all its defined objects from the DOM?
Im developing a simple framework that enables to load html fragments into a "main" html. Each fragment is self contained and may include references to additional JS and CSS files. The JS and CSS resources are parsed and dynamically added to the html. When the fragment is removed/replaced from the DOM I want to remove its JS and CSS.
If I remove the script element in the example below, the functions defined in page1.js are still available.
<html>
<head>
<script src="page1.js" type="text/javascript"></script>
</head>
<body>
...
Is there a way to unload page1.js objects from the DOM?
========= The test code I use =======
I tried the advice i got in the comments below; to delete the added objects using a cleanup function - but even this fails. The sources i used for testing:
<html>
<head>
<script type="text/javascript">
function loadJSFile(){
var scriptTag = document.createElement("script");
scriptTag.setAttribute("type", "text/javascript");
scriptTag.setAttribute("src", "simple.js");
var head = document.getElementsByTagName("head")[0];
head.appendChild(scriptTag);
}
function unloadJSFile(){
delete window.foo;
delete window.cleanup;
alert("cleanedup. typeof window.foo is " + (typeof window.foo));
}
</script>
</head>
<body>
Hello JavaScript Delete
<br/>
<button onclick="loadJSFile();">Click to load JS</button>
<br/>
<button onclick="foo();">call foo()</button>
<br/>
<button onclick="unloadJSFile();">Click to unload JS</button>
</body>
</html>
simple.js source:
var foo = function(){
alert("hello from foo");
}
This cannot be done.
When a script is executed, function definitions are added to the global window object. There may be debugging symbols attached to the function that indicate where the function came from, but this information is not available to scripts.
About the only way you could achieve something like this would be to create a pseudo-namespace in the script and then throw away that whole namespace when you are done with it. However, this question hints to me that you are trying to do something the wrong way. Perhaps elaborating on your scenario would help us provide alternate solutions.
No, that is not possible. You could build a simple cleanup function that removes all variables that were defined in that file:
var foo = 'bar';
var cleanup = function () {
delete window.foo;
delete window.cleanup;
};
// unload all resources
cleanup();
Another approach would be to use a modular object structure for your fragments, that clean up after themselves. That involves a slightly higher overhead but is probably worth it, as it makes the code much easier to read and maintain:
// creates the object using the second parameter as prototype.
// .create() is used as constructor
GlobalModuleHandlerThingy.addModule('my_module', {
create: function () {
this.foo = 'bar';
return this;
},
foo: null,
destroy: function () {
// unload events, etc.
}
});
GlobalModuleHandlerThingy.getModule('my_module').foo; // => bar
GlobalModuleHandlerThingy.unloadModule('my_module'); // calls .destroy() on the module and removes it.
perhaps you need to consider conditionally loading it rather than conditionally unloading it...
you can make them = null
function fnc1 (){
}
window.fnc1 = null
//or
window["fnc1"] = null
If you need to unload a specific object, it's fairly easy: just set it to {}
ie: myobj = {};
So if you know what objects are created in a particular include, it won't be hard at all.
On the other hand, if you don't know what objects are created in a particular include, there isn't a mechansim to find out - you can't ask Javascript to tell you what was defined in a particular include.
However, I would say that if you don't know what objects are being loaded in a particular javascript file, you're probably not doing yourself any favours in loading it (you should always have a reasonable idea what code does in your site), or in trying to unload it manually (if you don't know what it does, that implies its a third party include, which means that unsetting it manually is likely to break things).
Was researching for something like that myself and thought I'll post my findings
Wrap your stuff in a global namespace in js file so it can be removed easily, ie
var stuff = { blabla: 1, method: function(){} };
When you need to get rid of it, simply set stuff = {}, or null even
Remove script tag from page
*** If you use requirejs - require js remove definition to force reload
Note: as long as you don't reference modules inside the namespace from anywhere else everything will be collected by GC and you are good to go.
I figured a trick for this. I was wondering here days finding an answer for this and I just realized a perfect trick to do this without trying to unload the java Script. only you have to do is create a global variable like currentPage in your main page's java script and when you loading the page assign the page name to currentPage . then in every other .js file use $('document').ajaxComplete() insted of $('document').ready() add an if statement as first line inside every $('document').ajaxComplete() function. set it to check currentPage variable equals to a new page name. add all other events inside if statement. i don't know English very well so check my code. and This is my first answer here so sorry if i make some mistakes.
main.html
<body>
<div id='container></div>
<button id="load1">
<button id="load1">
</body>
main.js
var currentPage = "";
$(document).ready(function () {
$('#load1').click(function () {
loadSource('page1', 'body');
});
$('#load2').click(function () {
loadSource('page2', 'body');
});
});
function loadSource( page, element){
currentPage = page;
$('#container').load('views/' + page + '.php', element);
$.getScript('js/' + page + '.js');
$('#css').prop('disabled', true).remove();
$('head').append('<link rel="stylesheet" href="css/' + page + '.css" type="text/css" />');
}
all of my pages scripts and styles are in seperate folders views, js, css.
page1.html
<body>
<button id="test1">
<button id="test2">
</body>
page1.js
$(document).ajaxComplete(function () {
if(currentPage == 'page1'){
/*$('#test1').click(function () {
console.log('page1');
});*/
$('#test2').click(function () {
console.log('page1');
});
}
});
page2.html
<body>
<button id="test1">
<button id="test2">
</body>
page2.js
$(document).ajaxComplete(function () {
if(currentPage == 'page2'){
$('#test1').click(function () {
console.log('page2');
});
/*$('#test2').click(function () {
console.log('page2');
});*/
}
});
i commented one button in each script to check if that button still has old script's affect.

Add multiple window.onload events

In my ASP.NET User Control I'm adding some JavaScript to the window.onload event:
if (!Page.ClientScript.IsStartupScriptRegistered(this.GetType(), onloadScriptName))
Page.ClientScript.RegisterStartupScript(this.GetType(), onloadScriptName,
"window.onload = function() {myFunction();};", true);
My problem is, if there is already something in the onload event, than this overwrites it. How would I go about allowing two user controls to each execute JavaScript in the onload event?
Edit: Thanks for the info on third party libraries. I'll keep them in mind.
Most of the "solutions" suggested are Microsoft-specific, or require bloated libraries. Here's one good way. This works with W3C-compliant browsers and with Microsoft IE.
if (window.addEventListener) // W3C standard
{
window.addEventListener('load', myFunction, false); // NB **not** 'onload'
}
else if (window.attachEvent) // Microsoft
{
window.attachEvent('onload', myFunction);
}
There still is an ugly solution (which is far inferior to using a framework or addEventListener/attachEvent) that is to save the current onload event:
function addOnLoad(fn)
{
var old = window.onload;
window.onload = function()
{
old();
fn();
};
}
addOnLoad(function()
{
// your code here
});
addOnLoad(function()
{
// your code here
});
addOnLoad(function()
{
// your code here
});
Note that frameworks like jQuery will provide a way to execute code when the DOM is ready and not when the page loads.
DOM being ready means that your HTML has loaded but not external components like images or stylesheets, allowing you to be called long before the load event fires.
I had a similar problem today so I solved it having an index.js with the following:
window.onloadFuncs = [];
window.onload = function()
{
for(var i in this.onloadFuncs)
{
this.onloadFuncs[i]();
}
}
and in additional js files that i want to attach the onload event I just have to do this:
window.onloadFuncs.push(function(){
// code here
});
I normally use jQuery though, but this time I was restricted to pure js wich forced to use my mind for a while!
Mootools is another great JavaScript framework which is fairly easy to use, and like RedWolves said with jQuery you can can just keep chucking as many handlers as you want.
For every *.js file I include I just wrap the code in a function.
window.addEvent('domready', function(){
alert('Just put all your code here');
});
And there are also advantages of using domready instead of onload
Try this:
window.attachEvent("onload", myOtherFunctionToCall);
function myOtherFunctionToCall() {
// do something
}
edit: hey, I was just getting ready to log in with Firefox and reformat this myself! Still doesn't seem to format code for me with IE7.
I don't know a lot about ASP.NET, but why not write a custom function for the onload event that in turn calls both functions for you? If you've got two functions, call them both from a third script which you register for the event.
Actually, according to this MSDN page, it looks like you can call this function multiple times to register multiple scripts. You just need to use different keys (the second argument).
Page.ClientScript.RegisterStartupScript(
this.GetType(), key1, function1, true);
Page.ClientScript.RegisterStartupScript(
this.GetType(), key2, function2, true);
I believe that should work.
You can do this with jquery
$(window).load(function () {
// jQuery functions to initialize after the page has loaded.
});

Categories

Resources