On my AngularJS sample project, I know that I have a service method which SHOULD throw a JavaScript error.
Using Firebug, I confirm that a JS error is thrown when resolving a promise from a $resource (TypeError: phone.images is undefined); but, the error never appears in the Firebug console.
How can I get the resource to 'fail fast' and propagate the error up the call stack?
Here is the service code:
var phonecatServices = angular.module('phonecatServices', ['ngResource']);
phonecatServices.factory('Phone', ['$resource',
function($resource){
return $resource('phones/:phoneId.json', {}, {
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
});
}]);
Here is the controller (which fails silently):
phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', 'Phone',
function($scope, $routeParams, Phone) {
$scope.phone = Phone.get({phoneId: $routeParams.phoneId}, function(phone) {
//JS error SHOULD be thrown here:
$scope.mainImageUrl = phone.images[0];
});
...
}]);
I don't want the code to fail silently! How can I fix it?
Ideally, I would like to fix it throughout the framework, rather than putting in special error handling code for each service or resource call.
You need to add the error callback to your get call:
Phone.get({phoneId: $routeParams.phoneId}, function(phone){
// Do Stuff with phone object
}, function(error) {
alert("Y U NO RETURN PHONE?");
// Handle error accordingly
});
Here is the documentation for $resource
If you'd like to generically handle errors for AJAX requests through the angular framework, then you'd probably like something like an http interceptor (Check the interceptors section). This kind of paradigm requires that all requests pass through your interceptor service to be handled in a generic fashion.
Related
HI all i have 2 question
angular try to handle server $http error globally. so written below code in app.js
angular.module('mname',[])
.config(function ($provide, $httpProvider) {
$provide.factory('ErrorInterceptor', function ($q) {
return {
responseError: function(rejection) {
//console.log(JSON.stringify(rejection));
alert('Error:==>'+rejection.status+"===>"+rejection.statusText);
return $q.reject(rejection);
}
};
});
1) Here I can able to get that alert if 404 error.
But if server through any code error like missing variable or etc... but connection state is 200 .. that time how can i manage??
can't come inside this responseError: area .
2) I wrote one method for dialog factory to display the errors and message as Factory. I can able to include inside the controller to get working. How can use inside "responseError:" area . (refer above code)
My question is about $resource's interceptor(responseError). I want to emphasize that the angularjs I based on is V1.3.6.
Problem:
app.factory('authInterceptor',['$q', '$location', '$log', function($q, $location, $log){
$log.debug('this is a regular factory with injection');
return {
responseError: function(response){
console.log(response)
// problem is that I cant check 401 by response.status,
// because the response here is AN ERROR OBJECT like `SyntaxError: ...`. Anyway to get the status?
return $q.reject(response);
}
}
}])
When I get 401 response, responseError's arguments is AN ERROR OBJECT like SyntaxError: Unexpected token U because the reponse from server is plain text Unathorized with status 401.
But I want to get the response.status, and do something if it is 401.
Any help will be appreciated.
This question should be closed because I finally found answer myself.
When response is 401/404 and anything besides 200, transformResponse still executed and an error occurred! This error just cover the normal response(has status property), so I never get the original response inside interceptor!
I think it's stupid to execute transformResponse if the response's status is not 200! And inside transformResponse, you can't access status code...
Here is a simple interceptor that handles 401s, as well does some configuration:
angular.module('notesApp', [])
.factory('AuthInterceptor',['AuthInfoService', '$q', function(AuthInfoService, $q) {
return {
responseError: function(responseError) {
if (responseError.status === 401) { // authentication issue
//redirect user to login or do something else...
}
return $q.reject(responseError);
}
};
}])
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptor');
}]);
** Here is an interceptor that only intercepts incoming responses with a non-200 status code.**
If the status code is 401, the user is redirected to the login page. In this case, the promise is rejected so that the controller or service still sees a failure
The callback function for the POST is returning null for my custom HTTP header X-Auth-Token. Chrome is showing the correct POST response headers, but Angular.js is not.
The only ones Angular is returning are Cache-Control and Content-Type. Everything else shows null.
This is my CoffeeScript showing how I'm calling it:
.factory 'loginFactory', ($rootScope, $http, $resource) ->
$resource '/api/auth/login',
email: '#id'
password: '#id'
.controller 'userController', ($scope, $state, $http, loginFactory, userService) ->
$scope.validationError = false
$scope.user =
email: ''
password: ''
$scope.loginUser = ->
loginFactory.save $scope.user, (u, headers) ->
console.log headers('X-Auth-Token')
.$promise.then (response) ->
unless response.error
userService.login($scope.user.email, $scope.user.password)
unless userService.redirIfLoggedIn()
$scope.validationError = true
I also tried running earlier versions Angular 1.3.x, and those had the same issue.
Why is Angular only returning those two headers when I make a request?
Thanks for this solution goes to #dbugger who commented the answer I needed:
Looks like the server needs to give permission to see the headers. Check out this: Reading response headers when using $http of Angularjs
The proper way to make headers available outside of your local domain is to set: Access-Control-Expose-Headers on your webserver. In this particular case, you would put X-Auth-Token.
I'm new in the Angular world, so be nice with me :)
I use the Trello client.js in my Angular application to get data from Trello. For handling the authentication scenarios I'd like to use $http interceptors for catching any 401 responses and invoke the Trello authorization procedure accordingly. The code is a normal $http response interceptor, something like...
function trelloSecurityInterceptor($injector, $q, securityRetryQueue){
return {
responseError: function(originalResponse){
console.log('interceptor: ' + originalResponse.status);
$q.reject(originalResponse);
}
};
}
I use the Trello client like
function loadAllBoards(){
return authorize()
.then(function(){
var deferred = $q.defer();
Trello.get(
'members/me/boards',
function(result){
$log.debug('retrieved boards');
deferred.resolve(result);
});
return deferred.promise;
});
}
The problem is that the interceptor isn't being invoked. This is due to the fact that Trello internally uses jQuery ($.ajax).
Is there a way/shortcut to bind jQuery to Angular in a way to have $http interceptors fire properly or do I have to do it myself (using ajaxError on jQuery or similar)??
Thx
I've been hunting for a few hours now and can't seem to find any information specific to my setup so here goes.
I'm using the MEAN stack and wanting to use the Twitter API in my angular app. I have all the required keys and trigger a twitter api authentication on the server side using Node, then pass the token I get in response to my angular pages. I was hoping to be able to use this token to make requests to the api from an angular service. The request I'm trying to get working the moment is to fetch a given user's profile object. I've attached my service method below. The error I get when I run it is a 405 method no allowed, no access-control-allow-origin header is present.
angular.module('tms.system').factory('Twitter', ['$log', '$q', '$http', '$window', 'twitter', 'Global', function($log, $q, $http, $window, twitter, Global) {
return {
findProfile: function(handle) {
var deferred = $q.defer();
var config = {
timeout:3000,
headers: {
'Authorization': 'Bearer ' + Global.twitterToken,
'X-Testing' : 'testing'
}
};
$http.get('https://api.twitter.com/1.1/users/show.json?screen_name=' + handle, config).
success(function(data) {
$log.info(data);
deferred.resolve(data);
}).
error(function(status) {
$log.error(status);
});
return deferred.promise;
}
};
}]);
Just for future reference, as stated in the comments of maurycy's answer {and being myself trying to get tweets just from Angular without succes}, the best approach for this would be to get them from some backend.
I believe you should use $http.jsonp with a JSON_CALLBACK to get it to work, it's not going to happen with $http.get for sure