简体   繁体   中英

AngularJS: Trying to use a service, get error “cannot read property 'then' of undefined”

I'm trying to use authenticate with a JWT using my api in Laravel, and it works when I just do the authentication in the controller but I'm trying to do this proper and use a service, however I'm getting an error.

The thing is, when I refresh after the error, it redirects to the dashboard (set that up in app.js), which means a user is authenticated.

What am I doing wrong? Why is it giving me this error?:

TypeError: Cannot read property 'then' of undefined

...it should be redirecting to the 'dashboard' route. The error is at .then(function(data) in the controller.

Here is my service:

(function() {

    'use strict';

    angular
        .module('app')
        .factory('userService', ['$http', '$auth', userService]);

    function userService($http, $auth) {
        var service = {
            userLogin: userLogin
        };

        return service;

        function userLogin(credentials) {
            $auth.login(credentials)
                .then(function() {
                    $http.get('/api/v1/authenticate/user')
                        .success(function(res) {
                            return res;
                        })
                        .error(function(error) {
                            return error;
                        });
            });
        };
    };

})();

And here is my controller:

(function() {

    'use strict';

    angular
        .module('app')
        .controller('LoginController', ['$http', '$rootScope', 'userService', LoginController]);

    function LoginController($state, $rootScope, userService) {
        var vm = this;
        vm.login = login;
        vm.error;

        function login() {
            var credentials = {
                email: vm.email,
                password: vm.password
            };

            userService.userLogin(credentials)
                .then(function(data) {
                    if (data) {
                        var user = JSON.stringify(data.user);

                        localStorage.setItem('user', user);

                        $rootScope.currentUser = data.user;

                        $state.go('dashboard');
                    } else {
                        vm.error = error;
                    }
                });
        }
    }

})();

In the service, you should return a promise if you want to "then" the method. In that service, userLogin method is returning nothing.

You have to pass your service a callback, or use $q.deferred.

function userService($auth, $http) {
    return {
        userLogin: function(url, credentials, callback) {
            $auth.login(credentials).then(function(data) {
                $http.get(url).then(function(res) {
                    callback(res);
                });
            });
        }
    };
}

And in your controller

userService("/api/v1/authenticate/user", {password: "pwd", email: "me@me.com"}, function(res) {
    res.status; //200
    res.data; //whatever you got back from the GET request
});

To be more precise, you're getting cannot read property then of undefined because you're not returning anything to the original invoker. By default javascript will return undefined if nothing is returned, so you get undefined when you try to synchronously return an asynchronous function.

In service you can make use of $q service provided by angular like this

(function() {

    'use strict';

    angular
        .module('app')
        .factory('userService', ['$http', '$auth', '$q', userService]);

    function userService($http, $auth, $q) {
        var service = {
            userLogin: userLogin
        };

        return service;

        function userLogin(credentials) {
            var deferred = $q.defer();
            $auth.login(credentials)
                .then(function() {
                    $http.get('/api/v1/authenticate/user')
                        .success(function(res) {
                            // return res;
                            deferred.resolve(res);
                        })
                        .error(function(error) {
                            // return error;
                            deferred.reject(error);
                        });
                });

            return deferred.promise;
        };
    };

})();

And in controller you can call the service function as you are currently doing..

(function() {

    'use strict';

    angular
        .module('app')
        .controller('LoginController', ['$http', '$rootScope', 'userService', LoginController]);

    function LoginController($state, $rootScope, userService) {
        var vm = this;
        vm.login = login;
        vm.error;

        function login() {
            var credentials = {
                email: vm.email,
                password: vm.password
            };

            userService.userLogin(credentials)
                .then(function(data) {
                    if (data) {
                        var user = JSON.stringify(data.user);

                        localStorage.setItem('user', user);

                        $rootScope.currentUser = data.user;

                        $state.go('dashboard');
                    } else {
                        vm.error = error;
                    }
                });
        }
    }

})();

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM