I'm reading a book called MEAN Machine, and as I'm getting to the late chapters, I've got stuck at one of the sample applications, that doesn't seem to work.
The problem seems to occur because my mainController calls authService's Auth.getUser()
method, which may return either a $http.get()
or a $q.reject()
. As I'm not logged in, it returns $q.reject()
, and fails to chain the .success()
promise.
It throws following exception:
TypeError: undefined is not a function at mainCtrl.js:13
My code is as follows.
CONTROLLERmainController
angular.module('mainCtrl', [])
.controller('mainController', function($rootScope, $location, Auth) {
var vm = this;
// check to see if a user is logged in on every request
$rootScope.$on('$routeChangeStart', function () {
vm.loggedIn = Auth.isLoggedIn();
// get user information on route change
Auth.getUser()
/* ========= PROBLEM HERE ========= */
.success(function (data) {
vm.user = data;
});
});
// ... other stuff
});
SERVICEauthService
angular.module('authService', [])
// ===================================================
// auth factory to login and get information
// inject $http for communicating with the API
// inject $q to return promise objects
// inject AuthToken to manage tokens
// ===================================================
.factory('Auth', function ($http, $q, AuthToken) {
var authFactory = {};
// get the user info
/* ========= PROBLEM LEADS HERE ========= */
authFactory.getUser = function () {
if (AuthToken.getToken())
return $http.get('/api/me', { cache: true });
else {
return $q.reject({ message: 'User has no token.' });
}
}
What am I missing?
In AngularJS, the $q services has a top-level method, $q.reject (), which will create a promise that is immediately rejected with the given value. Ever since I saw this method, I have always wondered where the "resolve" equivalent was?
In AngularJS, the $q services has a top-level method, $q.reject(), which will create a promise that is immediately rejected with the given value.
If you create a promise with $q, AngularJS will automatically trigger a $digest whenever the promise is exercised, either with reject, resolve, or notify. If, however, you get a promise from a non-AngularJS source, then you don't have that digest-integration.
In AngularJS, the $q services has a top-level method, $q.reject (), which will create a promise that is immediately rejected with the given value. Ever since I saw this method, I have always wondered where the "resolve" equivalent was? If there's a $q.reject (), why not a $q.resolve ()? Well, it turns out there is.
Replace your call to the service with:
Solution A: .then(successCallback, errorCallback)
:
Auth.getUser().then(
function (response) { ... }, // success handler
function (response) { // error handler
// case where user is not logged in
// or http request fails
});
or
Solution B: .then(successCallback).catch(errorCallback)
:
Auth.getUser()
.then(function (response) { ... }) // success handler
.catch(function (response) { // error handler
// case where user is not logged in
// or http request fails
});
Your getUser
method is defined as follows :
authFactory.getUser = function () {
if (AuthToken.getToken())
return $http.get('/api/me', { cache: true });
else {
return $q.reject({ message: 'User has no token.' });
}
}
But the success
and the error
shorthand methods are specific to $http
. They doesn't exist in angular's promise $q
API. Therefore, when the user is not logged in, because you are returning a $q
promise, you got an undefined is not a function
.
The methods you can call on a $q
promise object are (link to documentation) :
then(successCallback, errorCallback, notifyCallback)
catch(errorCallback)
which is a shorthand for promise.then(null, errorCallback)
finally(callback, notifyCallback)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With