JQuery callback question - javascript

I'm trying to assign a different number to different callback functions in jquery.
for (i=o;i<types.length;i++) {
$('#ajax'+types[i]+'Div').html('Loading...').load('searchAjax.php','new=u',function () { $(this).find('select').change( function() { AjaxDiv(i); } ) } );
}
Everytime I run this section of code, i is 5 for each call to ajaxDiv because it is calling a global variable. I'm not sure if I can either change the scope of i or if there's a way to print the value in the change function. Any ideas?
Thank you in advance! Happy Thanksgiving!
Andrew

The callback functions all refer to the same i variable, and they are executed when the loop is finished.
You have to capture the i variable on the loop:
for (i=o;i<types.length;i++) {
(function (i) {
$('#ajax'+types[i]+'Div').html('Loading...').load('searchAjax.php','new=u',
function () {
$(this).find('select').change( function() { AjaxDiv(i); } )
} );
})(i);
}

Related

Javascript - How to put a callback in a callback?

I have read this:
Callback in a callback?
And I still do not understand how I am meant to do it. Sorry, I am a Python programmer and only just starting to understand JavaScript.
I have this function:
this.getName(function() {
alert("Done");
});
Which has a callback to here:
this.getName = function(callback){
*doing something*
callback();
}
Which works great. The alert doesn't go off until getName() has finished.
However I have another function, which needs to be run after getName() has been run and completed:
this.getDetails = function(){
*Does something*
}
But I haven't got a clue how it is meant to be implemented. I have tried putting it in the first function, but it doesn't work. Any help would be much appreciated!
I have tried this:
this.getName(function(getDetails) {
alert("Done");
this.getDetails();
});
Instead of alerting "done", just call getDetails (or do both):
this.getName( _ => {
this.getDetails();
} );
I switched to an arrow function to use lexical this, but if you don't want to use an arrow function you can also use bind:
this.getName( function ( ) {
this.getDetails();
}.bind( this ) );
or just:
this.getName( this.getDetails.bind( this ) );

Javascript Restart Timer From Within Closure

I'm trying to figure out how I can reset a timer created inside of an immediately invoking function from within the setTimeout closure. Here is my function:
var triggerHeightRecalc = function() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
}();
In the event that imagesLoaded() returns false, I receive the following error from attempting to call triggerHeightRecalc():
Uncaught TypeError: undefined is not a function
So I'm not sure if the issue is the function is not in the scope, or maybe it just cannot call itself? I've tried passing triggerHeightRecalc as a parameter in the setTimeout closure, but that doesn't seem to work either.
I've also tried this after reading this SO question:
var triggerHeightRecalc = function() {
var that = this;
var callback = function() {
if(imagesLoaded()) {
adjustHeight();
} else {
that.triggerHeightRecalc();
}
};
timeDelay = window.setTimeout(callback, 100);
}();
What am I doing wrong here, or is there a better way? Is this something that should be a setInterval() instead and I clear the interval when images are loaded?
Side Note: I'm calculating the height of a div inside a jQuery plugin, but I need to wait until the images are loaded in order to get the correct height (not sure if that is relevant).
Since you are invoking the function right from the declaration triggerHeightRecalc is getting set to the return of that function call, which is undefined since you in fact do not return anything.
You can do two things
1. Declare then invoke
var triggerHeightRecalc = function() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
};
triggerHeightRecalc();
2. Wrap the declaration in () and invoke
var triggerHeightRecalc;
(triggerHeightRecalc = function() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
})();
The second one will create a global variable unless you do the var triggerHeightRecalc; before hand.
Already answered, but I'll put this in.
First of all, if you just want to wait until all images have loaded you can use:
https://github.com/desandro/imagesloaded and then run the above code.
If that's not what you want, and you you just want a function that your setTimeout can run, then you can remove the () at the end of the function.
Here is what's happening in your current code
Your function is missing the opening bracket or similar character !+( (function.
Also your IIFE has no return keyword, and will return undefined to triggerHeightCalc.
If you do want an IIFE then you can either have a private version that is only callable within itself.
(function myModule(){
myModule(); //calls itself
})();
Or a public version that can be called both inside and outside.
var myModule = (function(){
return function myMod(){
myMod();
}
})();
myModule();
Patrick Evans has the right reasons, but there is a neater way to solve it :)
(function triggerHeightRecalc() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
})();
Here you are give an internal name to the (still) anonymous function. The name is only visible from within the function itself, its not visible in the global scope. Its called a Named function expression.

Javascript variable function does not persist values

This js function is part of a global variable. The first time it is called, from another js file, it works. But the second time, from itself, everything null.
Start: function () {
console.log('InactivityAlerts.Start() called ...');
if (this.active) {
if (this.IDLE_TIMEOUT != "") {
window.setInterval(this.CheckIdleTime, 1000);
console.log('started...');
}
else {
window.setTimeout(this.Start, 1000);
//an iframe sets the IDLE_TIMEOUT later, but this should continue to
//run until it is not blank.
}
}
},
When it calls itself again; however, everything is null, including this.active which was set from an Init prior to this. Why? And how can I make sure everything is still set right?
Thanks for any help
It's a this value issue, make sure you are binding the correct this value when passing functions around.
window.setInterval(this.CheckIdleTime.bind(this), 1000);
window.setTimeout(this.Start.bind(this), 1000);
You can also bind these at construction time if you always want them bound to the same instance.
function YourConstructor() {
//assumes that someFunction is defined on YourConstructor.prototype
this.someFunction = this.someFunction.bind(this);
}
Or the same with a well-known instance:
InactivityAlerts = {
Start: function () { /*...*/ }
};
InactivityAlerts.Start = InactivityAlerts.Start.bind(InactivityAlerts);

javascript inline callback function to separate function

Why is this code working:
function onCordovaReady() {
navigator.globalization.getLocaleName(function (locale) {
jQuery.i18n.properties({
name:'message',
path:'lang/',
mode:'map',
language:locale.value,
callback: function(){
alert(locale.value);
alert(jQuery.i18n.prop('msg_hello'));
alert(jQuery.i18n.prop('msg_complex', 'John'));
}
});
});
}
And this one not:
function onCordovaReady() {
navigator.globalization.getLocaleName(function (locale) {
jQuery.i18n.properties({
name:'message',
path:'lang/',
mode:'map',
language:locale.value,
callback: onLanguageReady(locale)
});
});
}
function onLanguageReady(locale) {
alert(locale.value);
alert(jQuery.i18n.prop('msg_hello'));
alert(jQuery.i18n.prop('msg_complex', 'John'));
}
I want to make the callback in a different function so my code will look cleaner, but couldn't get it to work. The first alert will work (it will display nl_NL), but the second and third alert will output [msg_hello] and [msg_complex].
Many thanks!
Try with this:
// beginning of code omitted
callback: function(locale) {
onLanguageReady(locale)
}
it is because you are assigning undefined to the callback property.
You are calling onLanguageReady and assigns that value to the callback method.
The solution is to use another function as callback function which will call the onLanguageReady function as given by #romainberger
function onCordovaReady() {
navigator.globalization.getLocaleName(function (locale) {
jQuery.i18n.properties({
name:'message',
path:'lang/',
mode:'map',
language:locale.value,
callback: onLanguageReady
});
});
}
function onLanguageReady(locale) {
alert(locale.value);
alert(jQuery.i18n.prop('msg_hello'));
alert(jQuery.i18n.prop('msg_complex', 'John'));
}
will work if the function calls back with locale.
the callback is expecting a function pointer that it can call once the processing is done when you say onLanguageReady(locale) you are actually executing the function and thus assigning the result of the function as the call back in this case the return is nothing thus undefined

Yet another javascript function scope question

In this code, the ident and data variables are correct in the callback, but I don't know how to pass in the right i for each loop iteration. I've tried reading up on functions and tried like 10 things, but alas, I must seek the wisdom of the stack.
function callback()
{
$(ident).html( data.fields[i].value );
$(ident).fadeTo('slow',1);
}
for(i=0;i<data.fields.length;i++)
{
ident='#'+data.rID+'_'+data.fields[i].field;
$(ident).fadeTo('slow',0,callback);
}
Change your "callback" function:
function callback(i) {
return function() {
$(ident).html( data.fields[i].value );
$(ident).fadeTo('slow',1);
};
}
Then in your loop:
$(ident).fadeTo('slow',0,callback(i));
This "callback" implementation returns the function that you'll pass to "fadeTo()".
One way would be to declare the callback function within the for loop.
My original answer was incorrect. Thanks to #Pointy for the heads-up.
This is similar to #Pointy's answer, but has different placement for the closure.
function callback(k) {
$( this ).html( data.fields[k].value );
$( this ).fadeTo('slow',1);
}
for(i=0;i<data.fields.length;i++) {
(function(j) {
ident='#'+data.rID+'_'+data.fields[j].field;
$(ident).fadeTo('slow',0, function() { callback.call( this, j) });
})(i);
}
You can use an anonymous function instead of the pointer to callback, so that you can pass in i to callback.
function callback(i, elem)
{
$(elem).html( data.fields[i].value );
$(elem).fadeTo('slow',1);
}
for(i=0;i<data.fields.length;i++)
{
var ident='#'+data.rID+'_'+data.fields[i].field;
$(ident).fadeTo('slow',0,function() { callback(i, this); });
}
Rather than making ident a global variable, it would be best to declare it (making it constrained to the current function's scope), and then use this in the callback to reference that element.
If you're not using callback anywhere else, it may make sense to just put its implementation inside of the anonymous function, rather than defining it separately and calling out to it:
for(i=0;i<data.fields.length;i++)
{
ident='#'+data.rID+'_'+data.fields[i].field;
$(ident).fadeTo('slow',0,function() {
$(ident).html( data.fields[i].value );
$(ident).fadeTo('slow',1);
});
}
The above example with the inline anonymous function doesn't work, because the reference to i is shared between the callbacks.

Categories

Resources