Yang Li Yang Li - 3 months ago 13
AngularJS Question

Angularjs ui-router login model example

I'm new to angularjs and bootstrap and I'm recently working on a web app which requires 2 different set of views (public and private).

For the public view, everyone can see it and it has it's own top menu navbar and the corresponding content.

For the private view, only authenticated users are able to see. The private view should have a totally different top menu and its corresponding content. (Maybe a side menu navbar but this is off topic).

I've read the api page for ui-router from here. And I've implemented the navigation like this. (plunker)

app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');

$stateProvider.state('public', {
'abstract': true,
views: {
'mainView@': {
templateUrl: 'public.html'
}
}
})
.state('home', {
parent: 'public',
url: '/',
templateUrl: 'home.html'
})
.state('login', {
parent: 'public',
url: '/login',
templateUrl: 'login.html',
controller: 'LoginController'
})
.state('private', {
'abstract': true,
views: {
'mainView@': {
templateUrl: 'private.html'
}
}
})
.state('dashboard', {
parent: 'private',
url: '/dashboard',
templateUrl: 'dashboard.html'
})
.state('settings', {
parent: 'private',
url: '/settings',
templateUrl: 'settings.html'
})
.state('logout', {
parent: 'private',
url: '/logout',
templateUrl: 'logout.html',
controller: 'LogoutController'
})
});


The example plunker I had above is working, but I'm not sure this is the "best" approach for handling such navigation. I'd very appreciate if someone can help me enhancing my solution.

Thanks in advance.

Answer

I like your approach and it looks clean. However, one thing I see it lacking is security. You can quickly add security by adding a resolve dependency.

Resolve

You can use resolve to provide your controller with content or data that is custom to the state. resolve is an optional map of dependencies which should be injected into the controller.

If any of these dependencies are promises, they will be resolved and converted to a value before the controller is instantiated and the $stateChangeSuccess event is fired.

The resolve property is a map object. The map object contains key/value pairs of:

key – {string}: a name of a dependency to be injected into the controller. factory - {string|function}: If string, then it is an alias for a service. Otherwise if function, then it is injected and the return value is treated as the dependency. If the result is a promise, it is resolved before the controller is instantiated and its value is injected into the controller.

.state('dashboard', {
    parent: 'private',
    url: '/dashboard',
    templateUrl: 'dashboard.html',
    resolve:{
        promiseObj:  function($http){
        // $http returns a promise for the url data
        // returns a promise so the resolve waits for it to complete
        // If the promise is rejected, it will throw a $stateChangeError 
        return $http({method: 'GET', url: '/someUrl'}); // confirm here that the user is logged in
        }
    })