JSONP request issue - extjs

Recently I have replaced xmlHTTPRequest with a JSONP request for my web service calls, but I found that I'm getting errors due to it. I could see that JSONP is a little slower.
initialize:function(){
this.callParent();
var jsonObject = Ext.create('MyProj.library.webservice').makeJSONPRequest('top_categories_json');
Ext.getCmp('categoryList').setData(jsonObject.info);
console.log(jsonObject.info);
}
makeJSONPRequest: function(urlx, postparams) {
Ext.data.JsonP.request({
params:{
params: Ext.JSON.encode(postparams)
},
success: function(result) {
console.log('JSON RES');
console.log(result.info);
if (result) {
//return JSON.parse(result);
return result;
} else {
Ext.Msg.alert('Error', 'There was an error retrieving the weather.');
}
}
});
}
I could see that after executing the makeJSONPRequest call, it executes the next stateemnt without waiting for the JSONP request to finish, so jsonObject becomes undefined. After that error the JSONP request finishes and prints the value. Anyway to suspend the main thread until the JSONP request finishes.

No. Calls to your service are async. You really need to put all logic in the callback handler. Or generates an event after you receive a response and handle that event.

Related

Angularjs analogue of jQuery .always()

I want to make a HTTP request to my server and can't find the answer on my question how to make .always() like in jQuery style.
According Angular's documentation of $http, there is only this construction:
// Simple GET request example :
$http.get('/someUrl').
then(function(response) {
// this callback will be called asynchronously
// when the response is available
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
There's the finally():
$http.get('/someUrl').
then(function(response) {
// this callback will be called asynchronously
// when the response is available
}.catch(error) {
// called asynchronously if an error occurs
// or server returns response with an error status.
}).finally() {
//Always do something
});
Which will always be called no matter what the outcome is.
You can read about this in the documentation for $q here.

angularjs break forEach in $http success

I have following code in Ionic framework,
var stopScan = false;
$scope.StopScan = function() {
stopScan = true;
};
$scope.ScanContacts = function() {
Contacts.unchecked().then(function(contacts) {
var promise = $q.all(null);
angular.forEach(contacts, function(contact) {
promise = promise.then(function() {
return $http.post(apiEndpoint+'/check', {number: contact.number})
.success(function(res) {
Contacts.update(contact.id, res);
if(stopScan)
// do break loop;
})
.error(function(err) {
console.log(err);
});
});
});
});
};
It's do sending http request in loop synchronously, and break on $http error, exactly like I wanted. But how I do break the loop in the $http success? I've tried throw 'Scan stopped'; and $q.reject('Scan stopped'); but no success.
First of all, angular.forEach does not support breaking (see here and here)
Second, break statement must be directly nested within the loop, even if it was a for or while loop.
And lastly, .success is happening asynchronously, after the loop has executed, so breaking there via some other mean would have been meaningless anyway.
It seems like you expect stopScan to be set asynchronously elsewhere (for example, in response to a click from the user), but you have to decide exactly what it means to stop - does it mean "do not make any more $http.post requests", or does it mean "make all the requests, but don't not process the response?". (Your example seems to imply the latter, because you're attempting to handle it in .success, but you should know, though, that POST typically implies that changes were made on the server).
You have to understand that once you kick off an HTTP request, it's going out (or it's pending, subject to max number of connections, which is browser-dependent).
So, what you could do is fire all of the requests at once and in parallel, and then manually "timeout" ($http supports a promise-based timeout) the ones that haven't been completed:
var stopScanTimeout = $q(function(resolve){
$scope.stopScan = function(){
resolve();
}
})
var promises = [];
angular.forEach(contacts, function(contact) {
var httpPromise = $http({ method: "POST",
url: apiEndpoint+'/check',
data: {number: contact.number},
timeout: stopScanTimeout })
.then(function(response){ return response.data; },
function(error) { return {error: error};});
promises.push(httpPromise);
});
Then you could handle all the results together, and some would be "errors" (but "soft" errors) if they were not completed in time:
$q.all(promises).then(function(results){
for (var i = 0; i < results.length, i++){
var result = results[i];
if (result.error) continue;
// otherwise, process the result
Contacts.update(contact.id, result);
}
})
If you want to run with parallel HTTP requests, then go with #NewDev's answer.
However if you want to stick with serial requests, then "breaking out of the loop" couldn't be simpler.
All you need to do is throw, which won't break as such but will send the constructed promise chain down its error path. At the stop point, there will be no unreturned requests and no more requests will be sent.
I would write something like this, using contacts.reduce(...) to build the chain.
$scope.ScanContacts = function() {
return Contacts.unchecked().then(function(contacts) {
return contacts.reduce(function (p, contact) {
return p.then(function() {
return $http.post(apiEndpoint + '/check', { number: contact.number })
.then(function(res) {
if(stopScan) throw new Error('scan stopped');
Contacts.update(contact.id, res);//you can choose to service the last response or not but placing this line above or below the throw line.
}, function(err) {
// As the second .then param, this callback will catch any http errors but not the 'scan stopped' error.
// By catching http errors, the scan will be allows to continue.
// To stop on http error, either remove this callback or rethrow the error.
console.log(err);
});
});
}, $q.when());
});
};
Here's evidence that throwing will give the required "stop" effect.
If throwing doesn't work in the real code, then it would seem that something else is wrong.

Property on $scope set inside of $http.success() is undefined outside of $http.success(). Why?

I am following an AngularJS tutorial that uses $resource to retrieve JSON data from an API call. For the purpose of understanding, I tried to replace the $resource code with $http code and I encountered a scope problem. Logging $scope.weatherResult outside of .success() results in undefined. Why is that the case? The view receives the data just fine.
Also,
// $scope.weatherAPI = $resource(
'http://api.openweathermap.org/data/2.5/forecast/daily',
{ callback: 'JSON_CALLBACK' }, { get: { method: 'JSONP' }}
);
// $scope.weatherResult = $scope.weatherAPI.get({ q: $scope.city, cnt: 2});
$http.get('
http://api.openweathermap.org/data/2.5/forecast/daily'
+ '?q='
+ $scope.city
+ '&'
+ 'cnt=2'
)
.success(function(data) {
$scope.weatherResult = data;
})
.error(function(error) {
console.log(error);
});
console.log($scope.weatherResult);
Because $http is asynchronous.
$scope.weatherResult is defined only when the http response is available.
See for example http://code.tutsplus.com/tutorials/event-based-programming-what-async-has-over-sync--net-30027, or better, as PSL says: How do I return the response from an asynchronous call?
You can use $watch to be informed:
$watch('weatherResult',function(newValue,oldValue)) {
..
}
When you write
.success(function(data) {
$scope.weatherResult = data;
})
in your program, you are asking the remaining part of your code to continue its execution with a promise.
In this case console.log($scope.weatherResult);
will be executed just after your $http.get() method without waiting for the response from the http request.
Hence, console.log($scope.weatherResult); will be executed even before the API response is received.
Note that $scope.weatherResult is defined inside .success(), so until the response is a success, Angular has no idea about $scope.weatherResult hence the console gives undefined. It will be undefined even in case of an error.
To view the response of server, you can log it well inside success block.
.success(function(data) {
$scope.weatherResult = data;
console.log("$scope.weatherResult = ",$scope.weatherResult);
})

Updating scope on form submit

I have a form that upon submit will POST a message to our REST API.
If successful, the REST API will return the updated value in the same JSON format as the GET call makes.
For some reason, even after the POST call has finished, the {{escalation.policy}} is still not updated in the scope.
var escalation = Escalation.save({
policy: $scope.policy,
}).$promise.then(function (data) {
$scope.escalation.push(data);
alert(data);
},
Is your REST request coming in then function? Try to put error function next to then() and make sure your request is successfully executed and responded back.
You need to call $scope.$apply() after $scope.escalation.push(data);. That will cause a new $digest to occur forcing the view to update, my guess is that $promise.then is ocurring outside the usual digest loop.
This is the current full segment of code for the submit()
$scope.submit = function () {
var Escalation = $resource('/api/escalation');
var escalation = Escalation.save({
policy: $scope.policy,
}).$promise.then(function (data) {
$scope.escalation.push(data);
}, function (error) {
alert('This request could not be processed. Please try again later.');
console.log(error);
});
};
The API will always return in the following format for a GET or POST:
{"policy":"Whatever the current/new policy is."}
Alas, i can still not seam to figure out why the view will not update.

How to handle a single 404 in AngularJS's $q

I have a couple chained $http combined with a single $http using $q.all([prmiseA, promiseB]). Everything is working fine, I get the data back and errors are handled no problem.
Except that on occasion data won't be found on a particular http call and it is not an error.
I am using a service to separate the logic from the UI. And my call looks like this
$scope.Loading = true;
var p = Service.Call(Param1, Param2);
p.then(function () {
$scope.Loading = false;
}, function (reason) {
$scope.Loading = false;
$scope.alerts.push({ msg: "Error loading information " + Param1, type: "danger" });
})
What I would like to be able to do is handling the 404 on that one URL inside the 'Service.Call' function. So that the UI code above remains untouched.
My problem is that if I add an error handler to the specific call that may return a 404. Then all errors are "handled" and so I loose errors for that one call.
Is there a way to "reraise" in $q?
Is there a way to "reraise" in $q?
Yes, you can rethrow by returning a rejected promise from the handler:
return $q.reject(new Error("Re Thrown")); // this is an actual `throw` in most
// promise implemenentations
In case an $http call 404 is not an error, you can recover from it. One of the cool features of promises is that we get to recover from errors:
var makeCallAndRecover(url){
return $http.get(...).catch(function(err){
// recover here if err is 404
if(err.status === 404) return null; //returning recovery
// otherwise return a $q.reject
return $q.reject(err);
});
}

Resources