0

Stuck with a simple basic login problem here. My AuthService factory has following code inside of it (2 relevant functions and a local variable):

  var username = '';

 function login(uname, upwd, utype) {

// create a new instance of deferred
var deferred = $q.defer();


$http({
        method: 'POST',
        url: '/root',
        headers: {
            'Content-Type': 'application/json'
        },
        data: {
            username: uname,
            password: upwd,
            type: utype
        }

    }).success(function(data, status, headers, config) {
        if (status === 200) {
            user = true;
            username = data.username;
            usertype = data.usertype;
            deferred.resolve();
        } else {
            user = false;
            deferred.reject();
        }

    })
    .error(function(data, status, headers, config) {
        user = false;
        deferred.reject();
    });

  // return promise object
  return deferred.promise;

}

function getusername() {

      return username;
    }

My controller looks like this:

angular.module('smApp').controller('rootloginController', ['$scope', '$location', 'notificationFactory', 'AuthService',
function($scope, $location, notificationFactory, AuthService) {

    $scope.submit = function() {
        AuthService.login($scope.rEmail, $scope.rootPassword, 'root')
        if (AuthService.isLoggedIn()) {
            $location.url('/dashboard');
            notificationFactory.success('Logged in as ' + rootEmail);
        } else {
            //ngNotifier.notifyError($scope.rEmail);

            notificationFactory.error('Invalid username & password combination');
        }
    };
    };
    }]);

I am calling my getusername() in the if statementright after login() and since login has $http post it's asynchronous and I think im hitting a wall here.

So my main problem here is the first click always gives me error message and the second clicks logs me in. I am assuming this has to do with the promise not being fulfilled right away and taking some time to execute. I was wondering if there was anyway around this? I really dont have any other code to execute beside wait since this is a login page and using a timeout doesnt seem like the proper way to do it.

  • why you create `deferred` object, if you not use it anywhere? – Grundy Nov 20 '15 at 08:55
  • I pasted the code wrong –  Nov 20 '15 at 09:06
  • Just a note, do not use $q within $http - there is no need to because $http returns a promise object anyway. See [the anti-pattern](http://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it) – br3w5 Nov 20 '15 at 10:12

2 Answers2

3

In this case you need to use the Promise API. Calls to the server made via the $http service return a promise, which allow binding of .success and .error methods.

The .then method may be used as a shorthand for both .success and .error. It accepts two functions that it executes in success and error scenarios respectively. Returning a promise in those functions allows chaining calls to the server.

In most cases, this should suffice:

// In service 
login: function () {
    return $http.post('your:url').then( // `then` here is optional, but possible
        function () {}, // update service values without having to involve the controller (and/or transform the response object)
        function () {}  // throw error log mesages
    )
}

// In controller
$scope.submit = function () {
    AuthService.login().then(
        function () {
            // success logic: redirect, assign scope variables, etc
        },
        function () {
            // error logic: allow retry
        }
    );
}
  • thanks! that helped. I have started look into the angular documentation for $q –  Nov 20 '15 at 09:46
1

You have to call AuthService.isLoggedIn() after the login request has been completed. For this, first return the promise of the deferred object you created.

function login(uname, upwd, utype) {
    // create a new instance of deferred
    var deferred = $q.defer();
    $http({ 
        method: 'POST',
        ...

    return deferred.promise;    
}

Now, you can wait for the request to complete.

AuthService.login($scope.rEmail, $scope.rootPassword, 'root').finally(function() {
    if (AuthService.isLoggedIn()) {
        $location.url('/dashboard');
        notificationFactory.success('Logged in as ' + rootEmail);
    } else {
        //ngNotifier.notifyError($scope.rEmail);

        notificationFactory.error('Invalid username & password combination');
    }
});
laszlokiss88
  • 4,001
  • 3
  • 20
  • 26