I use this function to retrieve an array from a web service.
button.onclick = function(item) {
var nonReplying = new Array(getNoreply(item));
console.log(nonReplying);
setTimeout(unInviteUsers(item, nonReplying), 2500);
}.bind(button, EventsArray[i][1]);
Then the function
function unInviteUsers(event,nonReplying)
{
//remember to parseInt() the first param, Event ID as well
for(var i = 0; i <= nonReplying.length; i++)
{
unInvite(event,parseInt(nonReplying[0][i].replace('"','').replace('"','')),AccessToken);
}
}
calls this function
function unInvite(event, user)
{
$.ajax({
url: 'https://graph.facebook.com/'+event+'/invited/'+user+'?access_token='+AccessToken,
type: 'DELETE',
success: function(result)
{
console.log(JSON.stringify(result));
}
});
}
But when button.onclick gets triggered some how the array nonReplying is not passed and unInviteUsers() returns
TypeError: 'undefined' is not an object (evaluating 'nonReplyingArray[0][i].replace')
And by the way, how do I properly force a function to wait until an other function is fully finished?
Is nonReplying actually a two-dimensional array?
Also, aside from the undefined error,
setTimeout(unInviteUsers(item, nonReplying), 2500);
will not do what you want. I believe you want that unInviteUsers to fire after 2.5 seconds. The first parameter of setTimeout needs to be a reference to a function. Unless unInviteUsers returns an anonymous function itself, this won't do the trick, but this might:
setTimeout(function() { unInviteUsers(item, nonReplying) }, 2500);
Related
I have a loop that calls executepostaction with an object. The problem is that executepostaction only execute the last value of the loop. I've tried many closures and here I am trying to fix using setTimeout but still no luck. What seems to be the problem?
my timeout function:
function MakeTimeout(fn, data, timeout) {
setTimeout(function () { fn.call(null, data); }, timeout);
}
This is the loop from an event function:
for (var ctr = 0; ctr < Selectrows.length; ctr++) {
var action= selectedAction;
action["trackId"] = Selectrows[ctr].innerText.replace(/(^\d+)(.+$)/i, '$1');
MakeTimeout(function (passaction) {
researchService.postExecuteAction(passaction)
.then(function (result) {
}, function error(result) {
$scope.error = result;
});
}, action, ctr * 1000);
}
Please help. Thank you
I see a few problems there, not sure exactly what you are trying to do but seems that you want to call a promise for each value of an array.
Guessing you are able to use ES6 and that each call are async, I would do something like this:
Selectrows.forEach(row => {
const action = {
...selectedAction,
trackId: row.innerText.replace(/(^\d+)(.+$)/i, '$1')
};
researchService.postExecuteAction(action)
.then(function (result) {
// Do something
}, function error(result) {
$scope.error = result;
});
});
First is using forEach instead of for if Selectrows is an array.
Clone the object selectedAction bc if you just assign it you are using the same object each time, bc objects and arrays are reference types.
Seems that you don't need a timeout, or do you? each promise will be executed in parallel and will response as soon as the promise return a response.
You can use spread syntax to create a copy of the object before modifying it.
var action = {...selectedAction};
Is it possible to pass a callback function that does not exist yet? My goal is to have a common function that will wait for another callback function to exist, when it does exist, it should execute it. This is what I have so far, but I can't figure out how to pass the function in that doesn't exist as a function yet.
function RunTemplateFunction(callback, userInfo) {
if ($.isFunction(callback)) {
callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(callback)) {
clearInterval(myInterval);
callback(userInfo);
}
}, 200);
}
}
I run the function like this:
RunTemplateFunction(MyFunctionToRun, GetUserInfo());
I get MyFunctionToRun is undefined for obvious reasons, I also tried the workaround of passing the function as a string and then convert the string to a function using eval(). But that throws the same error. I also thought of using the new function(), but that actually creates a new function.
Any help is appreciated. thank you.
If you call RunTemplateFunction by undefined there is no way we can see, is callback is defined or not, as we don't have reference to anything.
If you can modify the declaration to accept object as below, we can achieve what we want
function RunTemplateFunction(options, userInfo) {
if ($.isFunction(options.callback)) {
console.log('called1',userInfo);
options.callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(options.callback)) {
console.log('Called dynamically!!');
clearInterval(myInterval);
options.callback(userInfo);
}
}, 200);
}
}
var options = {}
RunTemplateFunction(options,{user:122});
options.callback = function(){
console.log("I'm called!!");
}
This will print
Called dynamically!!
I'm called!!
EDIT:
We can also call callback function in following way without setInterval, it will look different but options.callback variable is replaced by template.callMe function and its instantaneous also.
function TemplateRunner(userInfo){
this.callMe = function(cb){
this.templateFunction(cb);
}
this.templateFunction = function(callback){
callback(userInfo);
}
}
var template = new TemplateRunner({user:100})
template.callMe(function(user){
console.log('call me1',user);
});
template.callMe(function(user){
console.log('call me2',user);
})
This will print
call me1 {user: 100}
call me2 {user: 100}
Can I call a timeout function on the returned element in this if statement?
var data = 'some stuff';
if(data){
return jQuery('<div class="thisDiv"></div>').html(data);
}
I've tried the following:
if(data){
setTimeout(function() {
return jQuery('<div class="thisDiv"></div>').html(data);
}, 100);
}
But I get this error in my console:
Uncaught TypeError: Cannot read property 'nodeType' of undefined
The return statement will return from the anonymous function you passed into the setTimeout function, not the function enclosing the scope of the if statement. Try passing a callback into the function containing the if statement, then calling that callback with the data as a parameter.
function delayedReturn(callback) {
if(data) {
setTimeout(function() {
callback(jQuery('<div class="thisDiv"></div>').html(data));
}, 100);
}
}
No. You cannot use setTimeout to delay when a function will return. It is not a sleep function. It puts a function on a queue to run later, it doesn't stop all processing for a period of time.
function a() {
return 1;
}
var x = a();
In the above you have a single function which has a return statement. The value it returns is assigned to x.
function b() {
setTimeout(function c() {
return 1;
}, 1000);
}
var y = b();
Now you have two functions. b has no return statement, so it returns undefined and undefined is stored in y.
b uses setTimeout to call c, and c has a return statement. setTimeout doesn't do anything with return values though, so the return value of c is discarded.
Any time you are dealing with asynchronous functions, you have to do something with the data inside the asynchronous callback (such as call another function and pass the data as an argument). There is no going back, it is too late for that.
You could return a Promise from b though. That would allow other code to use the value of y to bind event handlers that will fire when the timeout expires.
You certainly can, you'd need to remove the return and use a valid selector to target your div.
Something like this would work:
HTML
<div class="thisDiv">test</div>
Javascript:
var data = 'some stuff';
if(data){
setTimeout(function() {
jQuery('.thisDiv').html(data);
}, 100);
}
You can see it working here: https://jsfiddle.net/ckkz1wbf/
Question, Why are you using:
jQuery('<div class="thisDiv"></div>')
Are you try to create an element, if that the case, you could use delay from jquery.
function fn(){
var data = 'some stuff';
if(data){
return jQuery('<div class="thisDiv"></div>').delay(100).html(data);
}
}
This question already has answers here:
Javascript infamous Loop issue? [duplicate]
(5 answers)
Closed 8 years ago.
Hello there I have the following problem - within a loop I have a certain number of jQuery ajax calls - in the return of the ajax call I want to use a local variable as well as the data returned by the ajax call:
In the JavaScript class DOCache.class.js (note that I use the global variable doCache here, which also does not "feel clean" but I do not know how to pass "this"):
function DOCache() {
this.cache = new Array();
this.capi = new JsonAPI();
// loads all the properties saved in the cache object
this.loadUpdateCache = function(allLoaded) {
for(var prop in this.cache) {
// a delay will be here for each object!
this.capi.get(this.cache[prop]['url'],(function(data) {
doCache.cache[prop]['data'] = data;
doCache.cache[prop]['ready'] = true;
if(doCache.cache[prop]['loaded'] instanceof Function) {
var propLoaded = doCache.cache[prop]['loaded'];
propLoaded(data);
}
// check all initialized
if(doCache.checkAllReady()===true && allLoaded instanceof Function) {
allLoaded(doCache.cache);
}
}) (prop) // KEY: If we have this, we get the correct prop - if removed, we get the correct data - but never both
);
}
};
}
In JsonAPI.class.js:
function JsonAPI(){
this.ajax = function(request_method,api_url,data,done,fail,always) {
var jqxhr = $.ajax(
{
type:request_method,
dataType: "json",
url: JSON_BASE+api_url,
data: data
},JSON_BASE+api_url,data)
.done(function(data) {
if(done instanceof Function) {
done(data);
}
})
.fail(function(data) {
if(fail instanceof Function) {
fail(data);
}
})
.always(function(data) {
if(always instanceof Function) {
always(data);
}
});
return jqxhr;
};
this.get = function(api_url,done,fail,always) {
return this.ajax('GET',api_url,"",done,fail,always);
};
}
The problem is that I do not know how to pass the local variable from the loop (which is a different string on each loop iteration) to the actual callback function without passing it explicitly using (prop) . But if I do this I do not get the data from the callback passed in.
So the actual question is: How can I use a local variable from an iteration (which obviously end before any ajax response is returned) in an Ajax callback function?
Try to aggregate your Ajax calls within an array. Then use $.when to set the callback:
var ajaxRequests = [];
var req1 = $.ajax();
ajaxRequests.push(req1);
$.when(ajaxRequests).done(function () {});
Note, this code is untested.
I have two functions, one that makes an Ajax request when the user loads the page, and one that will run every 5 or so seconds to update something. Using the first function, I can output a variable that I need to use in the second function.
function insert_last_ten() {
$.ajax({
url: 'freeshout/chatlog.php',
success: function(data) {
$("#inner-wrap").html(data);
var first_child = $("#inner-wrap :first-child").html();
var value = first_child.match(/(value)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?/);
var realtime = value[2];
}
});
}
Basically, I need to use realtime to do something else in another function. For the sake of simplicity, let's pretend this is the second function:
function update() {
alert(realtime);
}
How could I go about making that work?
In the success callback, cancel the timeout and start a new one using the updated value. You can pass the timeout identifier to insert_last_ten via argument and the success callback will pick it up via closure:
function createUpdateTimer(value, interval) {
return setTimout(
function () {
alert(value); // The created function knows what value is due to closure
}, interval);
}
function insert_last_ten(timer) {
$.ajax({
url: 'freeshout/chatlog.php',
success: function(data) {
$("#inner-wrap").html(data);
var first_child = $("#inner-wrap :first-child").html();
var value = first_child.match(/(value)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?/);
var realtime = value[2];
cancelTimer(timer); // This callbac knows what timer is due to closure
timer = createUpdateTimer(realtime, 500);
}
});
}
// Start the timer:
var timer = createUpdateTimer('initial value', 500);
// Make ajax request:
insert_last_ten(timer);
Note that I am only beginning to familiarize myself with the good parts of JavaScript. This code is untested.