Thursday, May 30, 2019

angularjs - Confusing $locationChangeSuccess and $stateChangeStart



I am trying to do some authentication with AngularUI Router. $urlRouter.sync() looks like exactly what I need. However, that's only available when I intercept $locationChangeSuccess. But when I do that, $state.current.name is empty, whereas I want it to be the current state.



Here's my code so far:



$rootScope.$on('$locationChangeSuccess', function(event, next, nextParams) {
event.preventDefault();

if ($state.current.name === 'login') {
return userService.isAuthenticated().then(function(response) {
var authenticated;
authenticated = response.authenticated;
return alert(authenticated);
});
}
});



Any pointers as to what I'm doing wrong?


Answer



I would suggest to go more "UI-Router way". We should use $rootScope.$on('$stateChangeStart' event where $state.current would be properly provided. Here is a working example



Let's observe simple (but not naive) solution, which could be extended to any degree later. Also if you will like this approach, here is much more comprehensive implementation: angular ui-router login authentication



Firstly, let's have our user service defined like this:



.factory('userService', function ($timeout, $q) {


var user = undefined;

return {
// async way how to load user from Server API
getAuthObject: function () {
var deferred = $q.defer();

// later we can use this quick way -
// - once user is already loaded
if (user) {

return $q.when(user);
}

// server fake call, in action would be $http
$timeout(function () {
// server returned UN authenticated user
user = {isAuthenticated: false };
// here resolved after 500ms
deferred.resolve(user)
}, 500)


return deferred.promise;
},

// sync, quick way how to check IS authenticated...
isAuthenticated: function () {
return user !== undefined
&& user.isAuthenticated;
}
};

})


So, we use async (here $timeout) to load user object form a server. In our example it will have a property {isAuthenticated: false }, which will be used to check if is authenticated.



There is also sync method isAuthenticated() which, until user is loaded and allowed - always returns false.



And that would be our listener of the '$stateChangeStart' event:



.run(['$rootScope', '$state', 'userService',

function ($rootScope, $state, userService) {

$rootScope.$on('$stateChangeStart', function (event, toState, toParams
, fromState, fromParams) {
// if already authenticated...
var isAuthenticated = userService.isAuthenticated();
// any public action is allowed
var isPublicAction = angular.isObject(toState.data)
&& toState.data.isPublic === true;


if (isPublicAction || isAuthenticated) {
return;
}

// stop state change
event.preventDefault();

// async load user
userService
.getAuthObject()

.then(function (user) {

var isAuthenticated = user.isAuthenticated === true;

if (isAuthenticated) {
// let's continue, use is allowed
$state.go(toState, toParams)
return;
}
// log on / sign in...

$state.go("login");
})
...


What we are checking first, is if user is already loaded and authenticated (var isAuthenticated = ...). Next we will give green to any public method. This is done with the data {} property of the state object definition (see Attach Custom Data to State Objects)



And that's it. In case of states defined like in a below snippet we can experience:





  • the 'public', 'home' are allowed to anybody

  • the 'private', 'private' will redirect to login if isAuthenticated === false

  • the 'login' in this example provides quick way how to switch isAuthenticated on/off



    // States
    $stateProvider

    // public
    .state('home', {
    url: "/home",

    templateUrl: 'tpl.html',
    data: { isPublic: true },
    })
    .state('public', {
    url: "/public",
    templateUrl: 'tpl.html',
    data: { isPublic: true },
    })
    // private
    .state('private', {

    url: "/private",
    templateUrl: 'tpl.html',
    })
    .state('private2', {
    url: "/private2",
    templateUrl: 'tpl.html',
    })

    // login
    .state('login', {

    url: "/login",
    templateUrl: 'tpl.html',
    data: { isPublic: true },
    controller: 'loginCtrl',
    })



Check that all here




Some other resources:




No comments:

Post a Comment

plot explanation - Why did Peaches' mom hang on the tree? - Movies & TV

In the middle of the movie Ice Age: Continental Drift Peaches' mom asked Peaches to go to sleep. Then, she hung on the tree. This parti...