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.
Related
I have a question about requests.I make first request then I suppose first onSuccess method will be runnning but program make second request immediately.How can i handle it? Context.getAlarmGroupById is called 2 times immediately.
my code:
function loadAll () {
Context.getAlarmGroupChainById({
id: $stateParams.id
}, onSuccess, onError);
function onSuccess(data, headers) {
vm.temp=data;
var numberGroupChain=vm.temp.length;
for(var i=0; i<numberGroupChain; i++){
vm.location.push(vm.temp[i].location);
vm.alarmChainList.push({name: vm.location[i],active:null,totalAlarmGroupNumber:null});
//loadData(vm.temp[i].id);
asyncLoop(vm.temp[i].id);
}
}
function onError(error) {
AlertService.error(error.data.message);
}
var index = 0;
function asyncLoop(chainId) {
if(index >= vm.temp.length) {
return;
}
Context.getAlarmGroupById({
id:chainId
}, onSuccess, onError);
function onSuccess(data,headers){
index++;
asyncLoop();
}
function onError(data,headers){
index++;
asyncLoop();
}
}
}
Firstly: Car.getGroupId is an asynchronous function. So you have to ensure that the previous call is completed, before the next call.
Secondly: The recursive function is created for replacing the loop, after the success function and index increment, the recursive function is called to ensure your required requirement.
Third: Change the calling sequence of asyncLoop(vm.temp[i].id); after loop:
Finally:
Please use the following code:
function loadAll () {
var index = 0;
function asyncLoop(chainId) {
if(index >= vm.temp.length) {
return;
}
Context.getAlarmGroupById({
id:vm.temp[index].id
}, onSuccess, onError);
function onSuccess(data,headers){
index++;
asyncLoop();
}
function onError(data,headers){
index++;
asyncLoop();
}
}
function onSuccessParent(data, headers) {
vm.temp=data;
var numberGroupChain=vm.temp.length;
for(var i=0; i<numberGroupChain; i++){
vm.location.push(vm.temp[i].location);
vm.alarmChainList.push({name: vm.location[i],active:null,totalAlarmGroupNumber:null});
//loadData(vm.temp[i].id);
}
asyncLoop();
}
function onErrorParent(error) {
AlertService.error(error.data.message);
}
Context.getAlarmGroupChainById({
id: $stateParams.id
}, onSuccessParent, onErrorParent);
}
Here is the pure JavaScript way to do this and it works perfectly fine. Use Promise.then(). Do like below:
var request1 = new Promise(function(resolve, reject) {
resolve('Success!');
});
request1.then(function(value) {
// make request2 here
});
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 this code:
us.isConnected()
.then(function (msg) { er.msg = msg }, function (msg) { er.msg = msg });
$interval(function () {
us.isConnected()
.then(function (msg) { er.msg = msg }, function (msg) { er.msg = msg });
}, 20 * 1000);
It checks for a connection and then outputs a message.
Is there a way that I could simplify this code and make it recursive so I would not have to code the .then part more than once?
You can use $timeout instead of relying on $intervals that may execute more than once isConnected() requests without waiting for the previously executed requests to finish.
var promise;
// execute testConnection()
testConnection();
function testConnection() {
// run request initially
return request().finally(function() {
// runs the request recursively
// and assign the timeout's promise
// if you need to cancel the recursion
return (promise = $timeout(request, 20 * 1000));
});
}
// request if ui is connected
function request() {
return ui.isConnected()
.then(setErr, setErr);
}
// ser `er` object
function serErr(msg) {
er.msg = msg;
}
// cancels the recursive timeout
function cancel() {
$timeout.cancel(promise);
}
var isConnected;
(isConnected = function () {
us.isConnected()
.then(function (msg) { er.msg = msg }, function (msg) { er.msg = msg });
})();
$interval(isConnected, 20 * 1000);
No recursion is necessary, unless it is necessary.
I'm brand new to angular, so I'm probably doing things all wrong. My query is returning an array of objects like it should be. I then do a click event to test the post..it hits my web api just fine...but then it returns that same array from my get. I'm guessing this is cached? Why would my post show the results of my earlier get?
Edit - Sorry, I could have been more clear. When I run my saveTest method, a post fires and my array saves, however the 'result' variable of that save..is the array from my original get.
app.directive('referenceSection', function () {
return {
restrict: 'E',
templateUrl: '/app/loanapplication/views/reference-section.html',
controller: function ($scope, referenceService) {
$scope.json = angular.toJson($scope.referenceArray);
$scope.referenceArray = [];
referenceService.query().$promise.then(function (result) {
$scope.referenceArray = result;
}, function () {
alert("fail");
});
$scope.saveTest = function () {
referenceService.save(angular.toJson($scope.referenceArray)).$promise.then(function (result) {
var x = result;
}, function () {
alert("save fail");
});
}
}
};
});
Service
app.factory('referenceService', function ($resource) {
var requestUri = '/api/reference';
return $resource(requestUri)
});
Web api
public class ReferenceController : BaseController
{
public HttpResponseMessage Get()
{
List<WebReference> references = new List<WebReference>();
WebReference reference = new WebReference();
WebReference reference2 = new WebReference();
reference.Name = "Andrew";
reference.Relationship = "QuickSupport";
reference.Id = 1;
reference2.Name = "Josh";
reference2.Relationship = "Hansen";
reference2.Id = 2;
references.Add(reference);
references.Add(reference2);
if (references == null) throw new HttpResponseException(HttpStatusCode.NotFound);
return Request.CreateResponse<IEnumerable<WebReference>>(HttpStatusCode.OK, references);
}
public HttpResponseMessage Post([FromBody]WebReference[] references)
{
try
{
var msg = new HttpResponseMessage(HttpStatusCode.Created);
return msg;
}
catch (Exception e)
{
throw new HttpResponseException(HttpStatusCode.Conflict);
}
}
}
}
referenceService.query().$promise.then(function (result) {
$scope.referenceArray = result;
After this, you need to call $scope.$apply() to inform angular of your changes made to be bound. If I guessed your question correctly .
:-)
From where you are reading response? From x that is not available outside then function or it is mistake to not attach it to referenceArray
referenceService.save(angular.toJson($scope.referenceArray)).$promise
.then(function (result) {
var x = result;
}, function () {
alert("save fail");
});
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);
});
}