I am following the tutorial related to Angular.js that is located on pluralsight.com. So far I did not have serious issues. Tutorials are very good and easy to follow. However, there is something that I cant resolve on my own. I would like my deffereds to react differently either on success or on fail. In this case they are always firing like they succeeded.
Service:
var resource = $resource('/data/event/:id', {id: '#id'});
return {
getEvent: function (id) {
var deferred = $q.defer();
resource.get({id: id},
function (event) {
console.log("This is (EVENT): " + event);
deferred.resolve(event);
},
function (response) {
console.log("This is (RESPONSE): " + event);
deferred.reject(response);
});
return deferred.promise;
Controller:
$scope.event = eventData.getEvent(2)
.then (
function(event) {
$scope.event = event;
console.log(event);
},
function(response) {
console.log(response);
}
);
In other words, if I send the wrong id (to load JSON file that does not exists) I want it to let me know that.
The $resource service in angular wraps a call to the $http service applying some REST conventions to the HTTP request. These are all documented here in the $resource docs.
When handling the promise from $resource, if the HTTP status code is 200, then the success callback will be executed. Otherwise (if the HTTP status code is in the 400 or 500 range), the error callback will be executed. This is a typical REST convention.
So, since your service is always returning 200 Status codes, $resource assumes that this is a successful server call and executes the success callback.
In order to handle this, you would need to use $http directly or change your service so that it returns the correct HTTP status code.
Hope this helps.
Related
Hello first of all thanks for your support,
I getting started with angular and I am trying to use conmsume data from an API for my app. I am having a few problems with this.
First of all CORS:
To run local http server I am using the one that comes with node.js (using http-server command).
I am using http://www.mocky.io/ to test the app. I've generated differents (with headers I've found around the net that are supposed to fix it) response there to try to fix CORS (always getting preflight error) but nothing seems to work.
I have added this to my save method (inside a factory):
save: {
method: 'POST',
headers: {
'Access-Control-Allow-Origin': '*'
}
}
If I use a Chrome extension called CORS I can bypass that and receive response but then I am not able to manage the promise and get the data inside the response. I would like to be able to show the response's json on the view.
$scope.submitForm = function() {
var promise = null;
promise = CheckFactory.save($scope.partner).$promise;
$scope.result = promise.data;
}
This functions sends the data from the form to the factory and perform the request but then I am lost and do not know how to manage the data I need from the response.
Thanks in advance :)
Basically you need to put .then function over your save method call promise. So that will call .then function's once data save request gets completed.
$scope.submitForm = function() {
CheckFactory.save($scope.partner).$promise
//it will called success callback when save promise resolved.
.then(function(data){ //success
$scope.result = data;
}, function(error){ //error
});
}
I would like to know the status code for the error in this function. I currently get this: GET http://localhost:3000/latest-live?lu=1448920013000 net::ERR_EMPTY_RESPONSE
Anyone know if I am handling my error function wrong? I know why I am getting the error, but to better handle the error I would like to know what the status code is (EX: status code 404 not found).
app.factory('getSpreadsheetData', ['$q', '$http', function($q, $http) {
return function getData() {
var deferred = $q.defer();
var req = $http({
url: 'http://localhost:3000/latest-live',
method: 'GET',
cache: false
});
req.success(function(object) {
var data = object.data;
deferred.resolve(data);
});
req.error(function(err) {
deferred.reject(err);
});
return deferred.promise;
}
}]);
Usually that error is thrown, if there is definitly no reponse from the server you are trying to reach in your URL.
Make sure that localhost is actually known to your system and something is running at port 3000 that can return something to your client.
Make sure that the route is known on your server /latest-live and that it didn't crash before returning any information.
First thing I would do is to check, if the URL is actually returning something, when you try to call it in your browser.
Update: Status Codes
Usually the status code is in the response, so you might want to check, if there is anything in err or response, depending on what function is called:
response.status – Number – HTTP status code
response.statusText – String – HTTP status text
Best regards
I'm learning Angular but having troubles to understand a point. I want to get data from my server. I used this code (from angular's doc) :
this.myFunction = new function()
{
var uri = this.getServerUri() + "Connexion/"+login+"/"+CryptoJS.MD5(pass);
var promises = $http.get(uri)
.success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
//alert("success:"+JSON.stringify(data));
return data;
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
return "";
});
return promises;
};
But I don't understand the behavior of the success function. When I call this function, it works fine, I get the server's answer but I get the full promises object (I have to write "promises.data" to get my data). Could you explain me why ? Because in the success function I tried to return only the data.
EDIT : I forgot to add my calling function :
var serverAccepted = this.MyFunction().then(function(promise) {
var objet = promise.data;
if(!_.isEmpty(objet))
{
userService.setUser(objet, true);
return "";
}
else return "Error while trying to login on the server";
});
return serverAccepted;
Thank you
A promise is a way of dealing with asynchronous requests without blocking. Instead of waiting for a slow operation (like waiting for the server to respond), before executing any more code, a promise is returned and code execution continues.
As such, when you call myFunction in your code above, it will return a promise object.
The promise then provides some neat methods for registering a callback to run code when the server does respond. These methods are .then() and catch() for the success and error case respectively.
Passing a function as an argument will call that function when the server has responded, and you can do with the data what you like. Take this example:
console.log("About to send request");
myFunction()
.then( function (myData){
console.log("Response received", myData);
})
.catch( function (myError){
console.error("Oh dear", myError);
});
console.log("Request sent!");
This will log the following to the console:
About to send request
Request sent!
Response received, {}
EDIT
In response to your comment:
why does the response received contains the full promise object and not only the data?
Because I return the data in the success function.
The response you receive does not contain a promise at all, but your function returns a promise. In your example serverAccepted is assigned the return value of myFunction() which is a promise and will not change.
The line:
.success(function(data, status, headers, config) {
return data;
})
Doesn't really do anything at all - returning a value from a .then() or .success() function is only useful if you are going to chain several calls to .then() together - it provides a way of manipulating values without an ever increasing pyramid of nested callbacks. Returning a value from within a promise callback (function passed to .then() or .success()) will not change the promise itself (serverAccepted in your case).
For example:
assume http GET some/url on your server returns:
{
foo: 'bar',
dorks: 12
}
When we use $http.get This data is inside the response object as a field called data. Most of the time we don't care much about the rest of the stuff, if the call was successful, we just want the data, so we can return it from the first .then() call (normally inside your service) so that any subsequent .then() calls (e.g. inside a controller) can access the data object directly.
myPromise = $http.get('some/url')
.then( function (response) {
console.log(response); //--> { status: 200, data: { foo:....}}
return response.data;
})
.then( function (data) {
console.log(data); //--> {foo: 'bar', dorks: 12}
return dorks;
})
.then( function (data) {
console.log(data); //--> 12
})
console.log(myPromise); //--> promise object with .then() .catch() etc
// ^ THIS WILL NOT CHANGE.
When I call this function, it works fine, I get the server's answer but I get the full promises object
Sounds like you are doing something like this:
var data = service.myFunction();
Above would be fine in synchronous world, however in case of asynchronous operations this is not correct usage of the promises. Instead you should use returned promise then/success methods:
service.myFunction().then(function(data) {
console.log(data);
});
$http request ,returns a promise with two $http specific methods: success and error. success function waits until request is to be finish with success (that means after $http promise resolves), and error function will execute only after the $http promise is rejected.
I have within my code that makes an $http.post to a back end, and of course things can go wrong. If I use the below syntax within angular:
$http.post(url).success(function(data, status, headers, config))
.error(function(data, status, headers, config));
If there is an error, I can retrieve the error code using status and handle it within the function defined in error(). However, if instead I take this approach (which is the one I am in fact using):
var deferred = $q.defer();
$http.post(url).success(deferred.resolve).error(deferred.reject);
return deferred.promise;
With the second syntax, I have all of my ajax calls within a separate ServiceJS directory, and can handle the successes or errors on a case by case basis. For instance, if the second snippet was Service.MyFunction() then in the code where I need it I would:
Service.MyFunction().then(function() {},
function(data, status, headers, config) {});
However, if I use this code block, status, headers, config are all undefined. My question is how can I retain this syntax but still retrieve the error code?
As an added reference, the back end is a C# Web API project, which would return errors using return BadRequest(); or the like.
Try something like this:
myFunction(){
var deferred = $q.defer();
// you can use .then() instead of .success or .error
$http.post(url).then(function(successResponse){
var data = successResponse.data;
var status = successResponse.status;
...
deferred.resolve(successResponse);
}, function(failureResponse){
var status = failureResponse.status;
var config = failureResponse.config;
...
deferred.reject(failureResponse);
});
return deferred.promise;
}
well, I'd say it's a good practice and more standard to implement a http interceptor and handle the HTTP errors from there intead of handling the error one by one on each http or resource object, and your code will be located in a single location.
basically, you can segment the actions to take depending on the error status you get for example:
angular.module('app').factory('myInterceptor', ['$q',
function($q){
return {
'responseError': function(rejection){
switch(rejection.status){
case 0:
//'No connection, is the internet down?'
break;
case 422:
// error
break;
case 484:
// error
break;
default:
// message rejection.status, rejection.statusText
break;
}
return $q.reject(rejection);
}
};
}
]);
$http is already returning a promise, so why not use that one?
function myFunction() {
return $http.post(url);
}
// ...
myFunction().success(function(data, status, headers, config) {
// ...
});
... or ...
myFunction().then(...);
The promises returned from $http have the methods success and error in addition to the other promise methods. Read more at Angular docs for $http.
I need to do a post request in which I'm not interested in the response (Fire And Forget)
I found a way on how to do this
xhr.onreadystatechange = function() { xhr.abort(); }
source
But in angular things are a bit different. For example, if using $http
var promise = $http.post(url, data);
I don't see how I can get the xhr object ? Any suggestions ?
As an alternative, you can use the timeout param on $http to cancel a request.
Beginning with AngularJS v.1.1.5 you can now even use a promise to abort the request:
var defer = $q.defer();
$http.get('/example', { timeout: defer.promise }).success(callback);
// [...]
defer.resolve();
So you want to make a post without caring about the answer? In that case you can just make and http request using $http.post(url, data) and then send some dummy response from the server (like true).