I use ajax in my code. I have to call connectHost() from $('SyncDataPort0') to $('SyncDataPort5'),
function connectHost()
{
ajaxFrame($('SyncDataPort0').value, getConnectStatus);
}
function getConnectStatus(transport)
{
try {
rs = transport.responseText;
if(rs == 'OK') {
//$('SyncDataState0').innerHTML = 'ok';
addStateMsg($('ConnectTest'),getMsg('msgConnectOk'));
} else //NOT OK
addStateMsg($('ConnectTest'),getMsg('msgConnectNotOkResult').replace('%s',rs));
}catch(e){alert(e)};
}
function ajaxFrame(url, pars, onCompleteFun)
{
if (3 in arguments)
addStateMsg(arguments[3],getMsg('msgDataSending'),0);
new Ajax.Request(url,
{
method:'post',
parameters:pars,
onComplete: function(transport)
{
var rs = transport.responseText;
if('logout' == rs)
location.href='/index.php?menu=logout';
else if('' == rs)
{
//do nothing
}else
onCompleteFun.apply(this,[transport]);
},
onFailure:function()
{
debug('Load Data Failure!');
}
});
return true;
}
The question is how can i implement the function without reproducing the getConnectStatus
callback function???
If you use an inline function declaration, you can refer to variables in the parent scope and you can pass the port to your connectHost() function.
function connectHost(portNum)
{
ajaxFrame($('SyncDataPort' + portNum).value, function(transport) {
// you can refer to portNum here in the callback
try {
rs = transport.responseText;
if(rs == 'OK') {
//$('SyncDataState0').innerHTML = 'ok';
addStateMsg($('ConnectTest'),getMsg('msgConnectOk'));
} else //NOT OK
addStateMsg($('ConnectTest'),getMsg('msgConnectNotOkResult').replace('%s',rs));
} catch(e) {alert(e)};
});
}
If you want getConnectStatus() to still be its own function, then you can use an inline stub function like this:
function connectHost(portNum)
{
ajaxFrame($('SyncDataPort' + portNum).value, function(transport) {
getConnectStatus(transport, portNum);
});
}
And getConnectStatus() will have the portNum as the second argument. You can pass as many arguments through to the callback as you like this way.
If getConnectStatus() needs the value of this preserved, then you would do this:
function connectHost(portNum)
{
ajaxFrame($('SyncDataPort' + portNum).value, function(transport) {
getConnectStatus.call(this, transport, portNum);
});
}
Related
Suppose that i have multiple ajax request that need to be called parallel.
The ajax request that need to be called is based on condition.
I can do it as below but it seems not feasible and trivial.
if (condition1) {
$.when(
apiRequest1();
).then(function(result1) {
});
} else if (condition 2) {
$.when(
apiRequest2();
).then(function(result1) {
});
} else if (condition 1 && condition 2) {
$.when(
apiRequest1();
apiRequest2();
).then(function(result1, result2) {
});
}
What i want to achieve is as follow. Concept is as follow but how can it be done?
var apiList = [];
if (condition1) {
append apiRequest1() to apiList;
}
if (condition2) {
append apiRequest2() to apiList;
}
if (condition3) {
append apiRequest3() to apiList;
}
if (conditionN) {
append apiRequestN() to apiList;
}
if (apiList has value) {
$.when(
apiList
).then(function (resultN) {
});
}
Arrays can handle that perfectly fine.
In each if () block, just append your promise to the array:
apiList.push(apiRequestN());
At the end, you need to pass each item as a separate parameter to $.when():
$.when.apply(null, apiList)
Try maybe this solution:
var async1 = $.ajax({//call 1
url:'http://mypage.com',
success: function(data1){
//data 1
}
});
....
var async2 = $.ajax({//call 2
url:'http://mypage.com',
success: function(data2){
//data2
}
});
$.when(async2, async1).done(function(result2, result1) {
console.log('done!')
});
var apiList = [];
if (condition1) {
apiList.push(apiRequest1());
} else if (condition 2) {
apiList.push(apiRequest2());
} else if (condition 1 && condition 2) {
apiList.push(apiRequest1());
apiList.push(apiRequest2());
}
Promise.all(apiList).then((result1, result2) => {
//Do your thing with the results
})
I am implementing long polling to know the state of some long running event on the server side. I create my own factory that will notify me when a server event triggers. Here is the factory.
.factory("$httpPolling", function ($http) {
function $httpPolling($httpService) {
var _responseListener, _finishListener;
var cancelCall = false;
var _pollId;
function waitForServerCall(id) {
console.log("executing waitForServerCall");
$httpService.get(href("~/polling/" + id))
.success(function (response) {
var cancelPolling = _responseListener(response);
if (cancelPolling || cancelCall) {
return;
}
else {
waitForServerCall(id);
}
});
};
function _sendData(httpMethod, url) {
var pollingId = guid();
_pollId = pollingId;
if (url.split("?").length == 2) {
url += "&pollid=" + pollingId;
}
else {
url += "?pollid=" + pollingId;
}
if (httpMethod == 0) {
$httpService.get(url).success(function (response) {
if (_finishListener) {
_finishListener(response);
}
cancelCall = true;
});
}
else {
$httpService.post(url).success(function (response) {
if (_finishListener) {
_finishListener(response);
}
cancelCall = true;
});
}
}
var $self = this;
this.get = function (url) {
_sendData(0,url);
return $self;
};
this.post = function (url) {
_sendData(1, url);
return $self;
};
this.listen = function (_listener) {
_responseListener = _listener;
waitForServerCall(_pollId);
return $self;
}
this.finish = function (_finish) {
_finishListener = _finish;
return $self;
}
}
return new $httpPolling($http);
});
Where the sintax of usage should be:
$httpPolling.get("url")
.listen(function(event){
// fires when server event happend
})
.finish(function(response){
// fires when the long running process finish
});
The problem is that _sendData method does not execute asynchronously because the waitForServerCall only executes the ajax call when the _sendData(long running process) method get the response from the server.
Why? Is this an angular behavior?
Angular $httpProvider has an option provided for async http calls, which is set to false as default value.
Try
app.config(function ($httpProvider) {
$httpProvider.useApplyAsync(true);
});
I have javascript code that is responsible for sending ajax requests and update the DOM:
this.AjaxPoller = {
poll: poll,
request: request
};
function request() {
$(".ajax_poller[data-url]").each(fetchDataForElement);
}
function fetchDataForElement(i, elem) {
var url = $(elem).data("url");
$.getJSON(url, handleJson);
}
function handleJson(data) {
if (checkProgress(data)) {
location.reload();
};
$.each(data, function(key, val) {
$(key+ ' .progress_info').html(val);
$(key + ' .progress-bar').width(val);
});
}
function poll() {
setTimeout(this.AjaxPoller.request, 5000);
}
function checkProgress(obj) {
var correct = true;
for (key in obj) {
if (obj[key] != '100%') correct = false;
}
return correct;
}
When using this code, this function returns the error that I write in the title:
function poll() {
setTimeout(this.AjaxPoller.request, 5000);
}
How can I change this code to make it work?
Instead of try this.
var AjaxPoller = {
poll: poll,
request: request
};
function poll() {
setTimeout(AjaxPoller.request, 5000);
}
As In case of
function poll() {
setTimeout(this.AjaxPoller.request, 5000);
}
this.AjaxPoller is undefined in this case as this keywork refer to a function poll() and does not contain definition of AjaxPoller.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
I created a simple example of my problem
The function count should count the numbers of items that I receive back from a query. However the way I am currently implementing it I lose reference to my function when I call from the route. In this case the function doWork is from another node module that I cannot modify.
Is there anyway to get around this
function Counter(){
this.array = createArray();
};
Counter.prototype.count = function (q){
query(q, function(data){
if(data === "tabe")
{
this.array[0].total++;
}
else
if(data === "chair")
{
this.array[1].total++;
}
else
if(data === "lamp")
{
this.array[2].total++;
}
});
};
createArray = function (){
var array = [];
array.push({item : "table",
total: 0});
array.push({item : "chair",
total: 0});
array.push({item : "lamp",
total: 0});
return array;
};
//The query function is actually in another node module that I cannot edit
query = function( data, callback){
callback(data);
}
module.exports = Counter;
index.js file
/* Process query */
router.get('/submit', function(req, res, next) {
var counter = new Counter();
counter.count("table");
counter.count("table");
counter.count("lamp");
for(var i = 0; i < counter.array.length; i++){
console.log(counter.array[i]);
}
res.end();
});
It is because the execution context of the callback method is not referring to the Counter instance, you can use the Function.bind() to pass a custom context to the callback method.
Counter.prototype.count = function (q) {
query(q, function (data) {
if (data === "tabe") {
this.array[0].total++;
} else if (data === "chair") {
this.array[1].total++;
} else if (data === "lamp") {
this.array[2].total++;
}
}.bind(this));
};
Another option is to use a closure variable
Counter.prototype.count = function (q) {
var self = this;
query(q, function (data) {
if (data === "tabe") {
self.array[0].total++;
} else if (data === "chair") {
self.array[1].total++;
} else if (data === "lamp") {
self.array[2].total++;
}
});
};
I am new to javascript programming. I just can't find an answer that works.
The problem is that my function only works when it is wrapped in setTimeout call like so:
var sPageIdentifier = 'ReportViewer';
UserPreferencesManager.Initialize(sPageIdentifier);
setTimeout(function () {
var strUserPrefs = UserPreferencesManager.GetPreferences();
console.log(strUserPrefs);
initLayout(strUserPrefs);
}, 1000);
function initLayout(strUserPrefs) {
//do stuff using strUserPrefs
}
If I comment out setTimeout function, the initLayout(strUserPrefs) fails because strUserPrefs is null.
Any help will be appreciated!
Here is the UserPreferencesManager.js code:
var UserPreferencesManager = function () {
var strPrefsID = null;
var strPrefsString = null;
return {
Initialize: function (strPrefsIDIn) {
strPrefsID = strPrefsIDIn;
strPrefsString = this.GetPreferences();
},
GetPreferences: function () {
if (!strPrefsID) {
alert("Validation Failed: the UserPreferencesManager must be initialized prior to usage.");
return null;
}
if (!strPrefsString) {
this.LoadPreferences();
return strPrefsString;
}
return strPrefsString;
},
LoadPreferences: function () {
if (!strPrefsID) {
alert("Validation Failed: the UserPreferencesManager must be initialized prior to usage.");
return null;
}
myasyncfunctioncall({
parameters: ["USR_PersonId", "abc", 'GET']
script_name: 'MAINTAIN_USER_PREFS',
onexception: function (exception, xhr, options) {
alert('Error: ' + xhr.statusText + +exception);
console.log(exception);
},
onsuccess: function (data, xhr, options) {
if (data == "User ID is zero") {
alert('MP_MAINTAIN_USER_PREFS: must be > 0.0');
strPrefsString = data;
}
else {
strPrefsString = data;
}
}
});
},// end of LoadPreferences
WritePreferences: function (strPrefsIn, strPrefsID) {
if (strPrefsID && typeof strPrefsID === "string") {
if (strPrefsIn != null) {
myasyncfunctioncall({
parameters: ["USR_PersonId", strPrefsID, strPrefsIn , 'SET']
script_name: 'MAINTAIN_USER_PREFS',
onexception: function (exception, xhr, options) {
alert('Error: ' + xhr.statusText + +exception);
console.log(exception);
},
onsuccess: function (data, xhr, options) {
if (data == "transaction-ok") {
UserPreferencesManager.LoadPreferences();
} else if (data == "User ID is zero") {
alert('MP_MAINTAIN_USER_PREFS: must be > 0.0');
}
}
});
} else {
alert("Error: Preferences object must be initialized prior to writing preferences");
}
} else {
alert('Error: The preference ID can\'t be null and must to be of type string');
return;
}
}// end of WritePreferences
};// end of return API
}(); // end of UserPreferencesManager
Seens like this myasyncfunctioncall is sending an async request. You'll need to add some variable to set if the response of this async request has arrived, and then, when it is set you can continue with your routine.
WHenever an async call is made on javascript, the program continues as if it was already completed. You have to mannually add checks to see if it has completed or not.
UserPreferencesManager.GetPreferences() is Making the asynchronous AJAX call to get the user preferences. So, in this case Javascript thread will continue execution in current thread context and executes initLayout(strUserPrefs). But at this state GetPreferences() call is still not complete and strUserPrefs is null.
SetTimeout is one of the trick to overcome this issue, which you did. But you can also design the APIs in such a way that it allows the callback function execution for each asynchronous AJAX calls.
Thanks for the tip, Balachandra!
Here is what I did, added two parameters to LoadPreferences method - callback and strPrefsID, so I can invoke fnCallback function within on success and pass it ajax data:
LoadPreferences: function (fnCallback, strPrefsID) {
if (!strPrefsID) {
alert("Validation Failed: the BhsUserPreferencesManager must be initialized prior to usage.");
return null;
}
if (strPrefsString) {
// strPrefsString is not null, so return it
callback(strPrefsString);
} else {
myasyncfunctioncall({
parameters: ["USR_PersonId", "abc", 'GET']
script_name: 'MAINTAIN_USER_PREFS',
onexception: function (exception, xhr, options) {
alert('Error: ' + xhr.statusText + +exception);
console.log(exception);
},
onsuccess: function (data, xhr, options) {
if (data == "User ID is zero") {
alert('MAINTAIN_USER_PREFS: must be > 0.0');
strPrefsString = data;
} else if (data.substring(0, 5) === "ERROR") {
alert(data);
} else {
fnCallback(data);
}
}
});
}
}// end of LoadPreferences
And here is how now I can call initLayout:
BhsUserPreferencesManager.LoadPreferences(initLayout, sPageIdentifier);