I'm having an issue with a prototype where I load pages through
$("#tab").load(/a/relative/pad);
The problem is that I'm unable to access the Javascript in the original environment, is there a way to get around this?
Javascript in the content of a loaded document does not get fired. What you can do is have a the callback of load fire the Javascript method you need.
If the function you need call after the load is dependent on the data you get back from the load, you can get the parameters you need during the callback of load.
$("#tab").load("/a/relative/pad", function(){
//find your parameter
var parameter = $("#parameter", "#tab");
//call your callback method
callback(parameter);
});
If no extra parameters are needed to make the callback:
$("#tab").load("/a/relative/pad", function(){
//call your callback method
callback(parameter);
});
Or if you prefer to not have an anonymous function:
$("#tab").load("/a/relative/pad", callback);
In all these cases callback is a function that exists on page A
Alternatively, while this is not in best practices, you could have a hidden block of text on page B that is actually a script block and you could call ecal() on that script.
$("#tab").load("/a/relative/pad", function(){
//get the block of script you need to run
var scriptToRun = $("#hiddenScriptBlock", "#tab");
//run the script
eval(scriptToRun);
});
Related
Following is a sample code created based on the scenario. showData() function is defined inside a javascript load function. I wanted to call showData() from another file maybe on a button click. I know this will work if the showData is made global. It's not possible to make the function global, as in this scenario it's a dynamically generated code. Is there anyway in JS that allows to call such functions ?
// Not possible to change the structure of this file as its coming dynamically
window.addEventListener("load", function() {
showData(); // 1st time call
function showData() {
console.log('starting execution')
}
});
// Calling from another file
showData(); // 2nd time call - not possible
No.
The function is declared inside another function. Its scope is that function.
Unless you change that code to make it a global, it isn't accessible from outside the containing function at all.
If the structure of the code can't be changed, perhaps you could try attaching your function to the global window object, like:
window.addEventListener("load", function() {
// attached to window
window.showData = function() {
console.log('starting execution')
};
window.showData(); // 1st time call
});
// Calling from another file
window.showData();
But make sure the second call (from the other file) has a little bit of a delay (remember the eventListener has to be attached to the window first, before the function becomes available).
You could try:
// second call
setTimeout(function() {
window.showData();
}, 1000);
I am using jquery for ajax calls
All the calls are called immmediately on page load and we are getting the responses at almost the same time.
the issue is, the 3 calls are fired and I am getting the data, but the callback function is fired for the first call only.
the other two callbacks are not called, the callback is defined as a separate function,
If I just write an alert instead of calling the callback method, all the 3 alert message are coming
So the issue is when we write the callback method, do any one have any idea of the strange behaviour?
We tried to reorder the calls, the behaviour is similar, which ever is called first, its callback will be called, for the rest, it will not be called
var url = "/test1";
ajaxCall(url, testMethod1, false);
var url = "test2";
ajaxCall(url, testMethod2, false);
var url = "test3";
ajaxCall(url, testMethod3, false);
testMethod1:function(data){
console.log("first"+data);
},
testMethod2:function(data){
console.log("second"+data);
},
testMethod3:function(data){
console.log("thrid"+data);
}
ajaxCall is defined as jquery ajax, the issue is only the testMethod1 is called, the rest 2 are not called
Regards
Hari
Well the thing that immediately caught my eye is that the URL for test1 has a forward slash preceding test1. This means that you are using a valid link in only test1. The alerts will trigger because you are probably not trying to access the data returned (which would still work even though the ajax request fails), where as you are trying to access the data in the coded call back functions you have provided, which will obviously throw a NullPointerException or whatever the equivalent as the ajax call fails due to an incorrect URL. Therefore data never gets set and the code doesn't work.
Suppose I load these scripts from my host webpage :
<script src="http://www.mywebsite.com/widget/widget.js?type=normal" type="text/javascript"></script>
<script src="http://www.mywebsite.com/widget/widget.js?type=rotation" type="text/javascript"></script>
and I'd like to execute the second one only when the first one have finished (totally; it can contain asynch functions).
How can I do it?
You're already doing it right : the scripts are executed in the order of integration in the page, not loading.
EDIT : as MaxArt pointed, this may not be what you're looking for. His answer is a good one.
But generally, you'll want to use javascript usual patterns and event based logic to avoid this kind of problems :
have most of your files define only classes and functions (some of them taking callbacks as parameters)
have a main file launching this and calling the sequence of actions, the asynchronicity being handled via callbacks.
My main code usually looks (a little) like this :
$(window).ready(function() {
var myBigEngine = new BigEngine();
myBigEngine.init(function(){
// do other things, no need to add other layers as user events and ajax message callback will do the rest
});
});
Wrap the whole script in a function, like this:
(function(id) {
var id = setInterval(function() {
if (!window.doneLoading) return;
clearInterval(id);
// The whole script file goes here
...
}, 50);
})();
The setInterval polls the (global, sorry) variable doneLoading. In the first script, you have to set doneLoading to true or any other non-false value when your async function is completely loaded, like at the end of an AJAX request maybe?
Edit: since I'm suggesting to add a global variable to the script, it may as well add a global function. So instead of setting up a setInterval call, wrap the second script inside a function... but like this:
function doneLoading() {
// The whole script file goes here
...
}
In the first script file, at the end of your callback function, just call doneLoading().
Try applying defer="defer" attribute to second <script> declaration like
<script src="http://www.mywebsite.com/widget/widget.js?type=rotation" type="text/javascript" defer="defer" ></script>
you can put second script init function in window.onload event
window.onload = function(){
// call function from second script
}
or with jQuery
$(function(){
// call function from second script
});
you can event add second script with this function
function loadScript(src){
var f=document.createElement('script');
if(f){
f.setAttribute("type","text/javascript");
f.setAttribute("src",src);
document.getElementsByTagName("head")[0].appendChild(f);
}
}
$(".delete").click(
function() {
var thesender = this;
$(thesender).text("Del...");
$.getJSON("ajax.php", {},
function(data) {
if (data["result"])
$(thesender).remove(); // variable defined outside
else
alert('Error!');
}
);
return false;
}
);
This can cause problems if user clicks on another ".delete" before the ajax callback is called?
It will fire another ajax request at the same time doing the same thing. Whether that causes problems or not depends on the server side of things.
Typically you're deleting an id or key of some sort...I assume later in this code you will be, but for now it just issues another delete and call to ajax.php...what the result of this is entirely depends on that PHP page.
The callback happens for that ajax request when that ajax request finishes, each request in independent in this respect, so each callback is individually handled. thesender is inside your current closure, so it's unique as well for each request and it's respective callback.
Each time the click handler is called, a separate closure will be created, so each the AJAX callback will have a reference to the correct variable.
Therefore, you don't need to worry about it. (Assuming that the server can handle the requests)
It will fire another event. You could use one rather than click if you want the event to only fire once. Alternately, you can keep track as to whether an AJAX request is in progress; e.g by using data as follows:
$('.delete').click(function () {
if ($(this).data('inProgress')) {
// Request in progress; cancel?
return;
} else {
$(this).data('inProgress', true);
};
});
You could also achieve the same thing by using a global variable, adding classes, etc.
I was implementing a on-demand script controller based on jquery's getscript, it looks like this:
function controller = function(){
var script = function(){
var scripts = {};
return {
load: function(jsurl){
$.getScript(jsurl, null);
},
run: function(js){
window[js].apply(this,null);
}
}
};
return {
script: script()
};
}
var ctlr = controller();
then here is a remote script with a function to be loaded - remote.js
function remotefunc(){
alert( 'remotefunc invoked' );
}
and here is how the whole thing supposed to work, in the main script:
ctlr.script.load( 'remote.js' ); // remote script successfully loaded
ctlr.script.run( 'remotefunc' ); // got an error, window['remotefunc'] undefined
but as you can see, 'remotefunc' is defined in the global 'window' scope, so the window object is supposed to be able to 'see' it.
I thought the problem was probably the closure stuff in the 'controller' definition, so I did a direct $.getScirpt without using the 'controller':
$.getScript( 'http://path/to/remote.js', function(){
window['remotefunc'].apply( this, null ); // this worked
} );
strange. So it is about the 'controller' implementation(I kind need it)! Anybody can help me out with this? How to fix the 'controller' implementation so the
window[js].apply(this,null);
can actually work?
Thanx.
The reason it's telling you window['remotefunc'] is undefined is because you are not giving it time to actually download and execute the remote script before attempting to call a function defined in it.
The remote script is loaded asynchronously, which means the script execution isn't paused while waiting for a response.
You will need to either re-implement the getScript method to be synchronous or somehow work your class around the fact that the function will not be available in any determinate amount of time.
EDIT: Just found another possible solution, try calling this before your request
$.ajaxSetup({async: false});
This will make the getScript method synchronous
When using something like getSript, it's important to remember that it is fetching asynchronously. Meaning, the browser fires off the request and while that's happening, code after that line executes without pause.
jQuery provides a callback function parameter to get script that allows you to do something after the asynchronous fetch is finished.
Try this:
var script = function(){
var scripts = {};
return {
load: function(jsurl, callback){
$.getScript(jsurl, callback);
},
run: function(js){
window[js].apply(this,null);
}
}
};
Then, when using it:
ctlr.load( 'remote.js', function(){
// remote script successfully loaded
ctlr.run( 'remotefunc' );
});
Could this be a timing issue?
In your working example you call the function in a callback which jQuery will not invoke until the script is loaded. In your non-working example, you call the function immediately after getScript which is asynchronously loading the script.