I have an application that is using ajax calls for loading the content. Those ajax calls are retrieving just the HTML. JavaScript is in another file.
After doing the AJAX-call I will call to a function that should start executing the JavaScript as soon as possible.
Here I leave a small function that will retrieve some code from an ajax call:
function loadPage(page) {
$(".container").html("");
if(page == "page1") {
$.ajax({
url: "/page1.php",
success: function(html){
$(".container").html(html);
loadPage1Script();
}
});
}else if(page == "page2"){
$.ajax({
url: "/page2.php",
success: function(html){
$(".container").html(html);
loadPage2Script();
}
});
}
}
After that, they will execute loadPage1Script() or loadPage2Script().
function loadPage1Script(){
//Start the carousel plugin, for example
}
A new code has been added to the HTML structure. Should I call to $(document).ready(); in the loadPage1Script() before executing the code to to attach all event handlers? Is there any differences if I do not do that? Will the script start faster if I add the $(document).ready(); ?
function loadPage1Script(){
$(document).ready(function(){
//Start the carousel plugin, for example
});
}
Taken from jQuery site(http://api.jquery.com/ready/):
"In most cases, the script can be run as soon as the DOM hierarchy has been fully constructed. The handler passed to .ready() is guaranteed to be executed after the DOM is ready, so this is usually the best place to attach all other event handlers and run other jQuery code."
If you are calling the loadpage function after you have aleady called
$( document ).ready( function () {
...
});
Then it shouldn't matter. Also, since the $.fn.html function isn't asynchronous, you will have no problem in running your loadPageScript functions straight away
There's no need to use $(document).ready() inside of those functions, because by the point they're run the DOM elements they need will already be present (you just inserted them into the page prior to calling the function).
You should, however, call the original loadPage function inside of $(document).ready() to ensure that the .container element(s) exist.
Related
I need to execute a function after a certain script was loaded so I load the script using an ajax call and on the success I invoke the function that uses an object that was suppose to be loaded already from that script and I get an error that this object is undefined.
Here is my code:
function LoadInlineManualScript() {
return $.ajax({
url: "../Scripts/inline-manual-player.js",
dataType: "script",
beforeSend: function () {
loader.hide();
loader.unbind();
},
success: SetInlineManualCallbacks
});
}
function SetInlineManualCallbacks() {
debugger;
//Here I get the error!
window.inline_manual_player.setCallbacks({
onTopicDone: function (player, topic_id, step_id) {
console.log('Step was displayed.');
}
});
}
And I get Uncaught TypeError: Cannot read property 'setCallbacks' of undefined.
I tried to change the call to use async:false but it didn't help.
Two things:
Function SetInlineManualCallbacks doesn't have a return statement. So despite issue 2, SetInlineManualCallbacks(inlineUid) should return undefined. However, success needs a function:
success: SetInlineManualCallbacks.bind(null, inlineUid)
Or old-school without bind:
success: function() {
SetInlineManualCallbacks(inlineUid)
}
But, looks like SetInlineManualCallbacks doesn't need any arguments, so this would be enough in your case:
success: SetInlineManualCallbacks
It says window.inline_manual_player is undefined. Judging from the variable name, I think it's because you just loaded the JS file content, as plain text, but you didn't execute the content as JavaScript.
You could use eval to execute it in success callback, but that's really a bad idea. I would probably insert a <script> tag into DOM, instead of using AJAX.
function LoadInlineManualScript() {
var s = document.createElement('script')
s.src = "../Scripts/inline-manual-player.js"
// your callback will fire when the script is loaded and executed
s.onload = SetInlineManualCallbacks
// it will start to load right after appended, and execute of course
document.body.appendChild(s)
}
Why you are loading by ajax? Let the browser do it.
The function loadScript insert the script on DOM and attach a callback to the event onload of script element.
function loadScript(href_script, callback) {
var script = document.createElement('script');
script.src = href_script;
script.onload = callback;
// The same code used by Google Analytics
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(script, x);
};
function SetInlineManualCallbacks() {
debugger;
//Here I get the error!
console.log("Code Running");
}
Here an example:
loadScript("//www.google-analytics.com/analytics.js", SetInlineManualCallbacks);
When you do this
success: SetInlineManualCallbacks(inlineUid)
You are executing the method and setting whatever it returns to the success callback. You are not saying call this when success is triggered.
It should just be
success: SetInlineManualCallbacks
But I think there is an issue with the Ajax call itself, you are loading a script and expecting it to do something, I do not think the Ajax call is what you want. If the script is just returning inlineUid why are you using a script and not a JSON or text call. If inlineUid is global, than just read it in the callback method. Without knowing what is happening in the script file, it is hard to give a full answer.
As someone suggested, Inline Manual is initialising itself in that script. You have your Site in Test mode, therefore there is an additional ajax request within the script itself, to check if the user can access it. So the script might load, but the inline_manual_player object won't be available yet when it is loaded because there are other things happening before it creates the object.
If you want to set the callbacks before the object is available, you can use queuing actions before calling the script to load.
var inline_manual_player = inline_manual_player || [];
inline_manual_player.push(['setCallbacks', my_callbacks]);
http://help.inlinemanual.com/docs/queuing-actions
This answer is a combination of some answers I got here:
The function I use to load the script instead of using Jquery's $.getScript is:
//Must load the script after inlineManualTracking object is ready.
function LoadInlineManualScript() {
loader.hide();
loader.unbind();
var script = document.createElement('script');
script.src = "../Scripts/inline-manual-player.js";
// your callback will fire when the script is loaded and executed
script.onload = WaitForInlineManualScriptToLoad;
// it will start to load right after appended, and execute of course
document.body.appendChild(script);
}
The script I load has use strict and it cannot be loaded with jquery because of the following reason: "use strict"; + jQuery.getScript() = script can't export to global namespace like epascarello mentioned earlier.
Even after using Leo's answer I still had a problem with that object and that's why I use the following function after the onload event of the script.
function WaitForInlineManualScriptToLoad() {
if (typeof window.inline_manual_player == 'undefined') {
setTimeout(WaitForInlineManualScriptToLoad, 100);
return;
}
InitInlineManualPlayerCallBacks();
}
function InitInlineManualPlayerCallBacks() {
window.inline_manual_player.setCallbacks({
onTopicDone: function (player, topic_id, step_id) {
console.log('Step was displayed.');
}
});
}
This works! it's not the prettiest, but it works. The developer of inline-manual tool had responded here(Marek) and mentioned the fact that my site in under "Test" mode. There was no way we could know this can affect.
According to your question you want to execute a skript, after another script was loaded correctly.
In your own answer using the jQuery "getScript"-function won´t work for you, so why not trying the old-fashioned way without using jQuery after all?
Create a new script-element, add it to your document head and set a callback-function on readystate.
function loadScript(url, callback) {
var newScript = document.createElement( "script" )
newScript.type = "text/javascript";
if(newScript.readyState) { //IE
newScript.onreadystatechange = function() {
if (newScript.readyState === "loaded" || newScript.readyState === "complete") {
newScript.onreadystatechange = null;
callback();
}
};
} else { //Others
newScript.onload = function() {
callback();
};
}
newScript.src = url;
document.getElementsByTagName("head")[0].appendChild( newScript );
}
Now you can call the defined method and offer a callback-function, in your case this would be:
loadScript("../Scripts/inline-manual-player.js", function() {
debugger;
// should work now
window.inline_manual_player.setCallbacks({
onTopicDone: function (player, topic_id, step_id) {
console.log('Step was displayed.');
}
});
});
It seems the script wasn't executed at that time. Please note the callback is fired once the script has been loaded but not necessarily executed, based on JQuery documentation.
If you want to make sure the script was executed, you can load the script synchronically on the HTML before you use it. If you do this, you won't need ajax, and you will keep your code simple. KISS principle
If you need to do it the way you have it here, then you can apply the observer pattern creating a custom event.
Here is an example.
At the end of the file "inline-manual-player.js". You can do something like this.
$.event.trigger({
type: "fileExecuted");
Then instead of the success callback, you would subscribe to the "fileExecuted" event.
$(document).on("fileExecuted", SetInlineManualCallbacks);
Hope it helps.
success takes a function and not a value. Unless SetInlineManualCallbacks returns another function, use bind and partially apply arguments.
function LoadInlineManualScript() {
return $.ajax({
url: "../Scripts/inline-manual-player.js",
dataType: "script",
beforeSend: function () {
loader.hide();
loader.unbind();
},
success: SetInlineManualCallbacks.bind(null, inlineUid)
});
}
It would help if you explained where inlineUid comes from.
It would appear that inline-manual-player.js loads window.inline_manual_player asynchronously. This means the thread is allowed to move on after that file's onload event fires but before window.inline_manual_player is loaded. Thus, you're finding that window.inline_manual_player is undefined for a period. This is probably due to inline-manual-player.js making ajax calls of its own (or setTimeouts, etc. - JavaScript is an asynchronous beast).
Rather than setting an ugly (no offense) setTimeout, there are two potentially better possibilities.
1
If you're willing and able to update inline-manual-player.js, you could put something like this at the top of that file:
window.inline-manual-player-callback-queue = [];
... and later in that file, after window.inline_manual_player is asynchronously defined, add:
// I've made this an array, in case you'd like to add multiple functions to be called upon window.inline-manual-player being ready.
var queue = window.inline-manual-player-callback-queue;
var length = queue.length;
var i = 0;
for(i; i<length; i++) {
queue[i]();
}
Finally, in your initial file, input the following:
function addCallback() {
window.inline_manual_player.setCallbacks({
onTopicDone: function (player, topic_id, step_id) {
console.log('Step was displayed.');
}
});
}
$.ajax({
url: "../Scripts/inline-manual-player.js",
dataType: "script",
beforeSend: function () {
loader.hide();
loader.unbind();
},
success: function() {
// Because you've defined window.inline-manual-player-callback-queue at the start of inline-manual-player.js, the following will be available upon onload (aka success) of that file:
window.inline-manual-player-callback-queue.push(addCallback);
}
});
2
If editing inline-manual-player.js isn't an option, the initial author of that file may have already included something akin to window.inline-manual-player-callback-queue. Check the documentation of the file, and see if there's not a global method or array you can add your callback function to, to have inline-manual-player.js call it automatically, once all the async magic has taken place.
Best of luck to you!
We have started using jquery load in our site to load contents into a div rather than re-loading whole page. However in the complete function we have a method that re-applies various bindings. Is it possible to provide load method with a default complete function? So developers don't have to specify it in the jquery load complete function.
As we currently are providing a lot of duplicate complete functions
E.g.
$('#Target').load(callBackRedirect, function () {
ApplyBindings('#Target');
});
These bindings can't be applied using on and need to be re-applied on page loads. We also do some other work that we want to do on every page load.
The answer is no.
You need the callback because that's what the method calls when the request is done.
This works with on method to, you might be doing something wrong out there in the code.
You could create a helper function for this.
function loadSomething(targetElement, uri,callback) {
targetElement.load(uri, callback);
}
loadSomething(
$('myElement'),
'mylink.com/content',
function() {
applyBindings($(this));
}
)
Yes. Check out the list of Global AJAX Event Handlers.
e.g.
$(document).ajaxComplete(function() {
alert('Triggered ajaxComplete handler.');
});
That said, you shouldn't need to reapply your bindings after an AJAX call. If you need to do this, you're probably doing something wrong. Check out jQuery.on, which explains how to bind to content which is added dynamically.
Try $.ajaxSetup:
$.ajaxSetup({
complete: function() {
ApplyBindings('#target');
}
});
EDIT
You could also make a named function like:
var ajaxApplyBindings = function() {
ApplyBindings('#Target');
// anything else...
};
And then pass it to load:
$('#Target').load(callBackRedirect, ajaxApplyBindings);
I am loading my partial views in a page using $("div").load(url) event. So that Page will render faster. But with this $(document).ready is getting fired even before the content gets loaded.
I have tried $(window).load also, but this is also getting fired even before the content loading.
Can you please suggest a way to wait until the data gets loaded then only execute my javascript functions.
When you are using $("div").load(url), You are loading the url content asynchronously.
Which means that document.load is first initialised and then async call is made to load(url).
Put all your initialization Javascript in a Function (lets say myinit() ) and fire it on success call back of your load method
Eg
// this line keeps all your function in one global name space and you can extend it multiple times in same document or js files
var myapp = myapp||{};
$(function(){
// Here you are extending your myapp object with custom init function
myapp.init = function(){
//your init code here
}
//your ajax content load here
$('div').load(url,function(){
//Here you call it
myapp.init();
})
})
P.S. you can always test your custom methods in console using myapp.init() anywhere in jQuery exec block
I need to be sure that a certain script within a page is executed as last.
I thought of using JQuery
$(document).ready( ... )
but if there are more functions of this type, which is actually executed last?
There are many ways to delay the execution of a script.
There is no way to programatically detect all of them.
For a reliable solution you would have to reverse engine the code of each page you care about, figure out what it is doing (and when) and write your delay script specifically for that page. (For a value of "reliable" equal to "until they change the page").
$(document).ready( ... )
is not executed last. The last function executed ( so, after document ready ) is the one(s) from <body onload>.
Example : <body onload="myJSfunction();">
Here, the javascript myJSfunction is executed at the end, after $(document).ready( ... ).
This depends on the order in which you have registered them.
E.g:
$(document).ready( function() { alert("first"); });
$(document).ready( function() { alert("second"); });
$(document).ready( function() { alert("third"); });
would alert "first" then "second" then "third"
So adding a <script> to the bottom of your page with an $(document).ready( yourfunction ); would suffice.
Theoretically you can do something like this:
// Form array of functions which sould be called with according order
$.readyArray = [function () { ... }, function () { ... }, function () { ... }, ...];
// just execute them in this order when onready event
$(document).ready(function() {
for (var i = 0; i < $.readyArray.length; i++) {
//apply, calls function in current context and pass arguments object
$.readyArray[i].apply(this,[arguments]);
}
});
If refactoring (as Quentin suggested) is not an option (e.g. you are updating a just part of a framework or a product), you can use four approaches, which should give you a good chance achieving what you need. See the following snippets with jQuery:
(1) Wait until 'document' is ready
By document is meant the visible DOM. The script will fire when all it should be rendered really rendered is.
$(document).ready(function() {
console.log('Document is ready.');
});
(2) Wait until top-level JS (Root) 'window' object is ready
The full root object can (will) be ready some time after the DOM is ready.
$(window).ready(function() {
console.log('Window is ready.');
});
(3) Wait until 'window' is fully loaded using .bind
This fires immediately after 'window' is ready, so your script can act on objects (elements) rendered during $(window).ready() above.
$(window).bind("load", function() {
console.log('Window bind is ready.');
});
(4) Wait until Ajax calls are completed
This is as far as you can go - the script will fire when 'window' is ready, loaded, all the code run and all the Ajax actions are completed. Unfortunately, since one Ajax can call another one, it can fire several times during the page load.
$(window).ajaxComplete(function() {
console.log('Window bind is ready, Ajax finished.');
}
In simple Javascript solution, you could call the javascript function at end of your HTML document inside the script tag. This works well when you are not using jQuery.
In case of jQuery you could use load method.The load event is sent to an element when it and all sub-elements have been completely loaded.
For more info look at
http://api.jquery.com/load-event/
Try this,
$(window).bind("load", function() {
//code here
});
The application I am looking at loads an external javascript file which looks like this:
$(function () {
// Don't allow browser caching of forms
$.ajaxSetup({ cache: false });
var dialogs = {};
var getValidationSummaryErrors = function ($form) {
// We verify if we created it beforehand
...
...
}
return errorSummary;
};
I understand that the file setups up some variables and also declares a function called getValidationSummaryErrors.
What I don't understand is why is this all within
$(function () { ... }
What's the purpose of this? Can I not just declare the variable and things inside the flat file without the "$(function () { }" ?
$(function() { ... }); is just short for $(document).ready(function() { ... });, which ensures that the code is not executed until the DOM is ready, otherwise some code that affects the DOM may not work properly.
See http://api.jquery.com/ready/
$() is shortcut for jQuery.ready(), which executes code after page DOM is fully loaded. Sometimes you want to make sure that document is ready before you do certain things.
$(function () { ... });
Means that the function will run after the page (DOM part) is loaded, not when the code gets parsed. This you can make sure that the page is loaded faster, and also everything necessary is available for the javascript to run.
This is a concise notation for $(document).ready(function() {...}) ". NOTE : the jQuery document ready fires when the DOM has been loaded. It doesn't wait for entire page (included images and the like) to load.
Practically, any script that you put into the <head> executes immediately i.e. if the Script interacts with the DOM it needs to be ready.
Thirdly it is needed for separations of concerns. Ideally your javaScript and HTML are in separate files. If you follow this you will not have any in-line script tags in your HTML at all.