Skip to content Skip to sidebar Skip to footer

AngularJS UI-Router + State Help Needed

I have html code (code snippet 1) & JS code (code snippet 2) as below. In html I am including the partials and building a page that contains a ui-view which dynamically change

Solution 1:

If I've understood it correctly you want to display the login view with-out the other views like header, footer & side menu.

Then you could create an abstract state for the layout with your views header, footer, side-menu etc. and add a separate state for your login view.

The tricky part of the demo is the views definition in the abstract state:

abstract: true,
views: {
    '': {
        templateUrl: 'layout.html',
    },
    'header@root': {
        template: 'content for header'
    },
    'footer@root': {...}
}

What is the abstract state doing? The abstract state will load the layout template in the unnamed view in your main template and loads the other views that you'd like to share with the child states.

Each child state can then define the content view as needed and re-use the other views.

Please have a look at the demo below or this fiddle.

Note: The login in the demo is of course not secure and only there to show the view redirect handling. In your app you have to work with $http and with sessionStorage and tokens.

angular.module('demoApp', ['ui.router'])
	.run(function($rootScope, $state) {
            $rootScope.$on('$stateChangeError', function(evt, to, toParams, from, fromParams, error) {
          if (error.redirectTo) {
            $state.go(error.redirectTo);
          } else {
            $state.go('error', {status: error.status})
          }
        })
    })
	.factory('userService', userService)
	.config(routes);

function userService() {
	var usersMock = {
    	'testUser': {
        	username: 'testUser',
            password: '1234'
        },
        'testUser2': {
        	username: 'testUser2',
            password: '1234'
        }
    };
	var userService = {
    	user: undefined,
    	login: function(userCredentials) {
        	// later --> $http.post('auth', userCredentials).then(...)
            // for demo use local data
            var user = usersMock[userCredentials.username]
            userService.user = ( user && ( user.password == userCredentials.password ) ) ? 
            	user : undefined;
            return user;
        },
        logout: function() {
        	userService.user = undefined;
        }
    }
    
    return userService;
}
function routes($urlRouterProvider, $stateProvider) {

	$urlRouterProvider.otherwise('/');
    
    $stateProvider
    	.state('root', {
        	url: '',
        	abstract:true,
            resolve: {
            	'user': function(userService) {
                	return userService.user; // would be async in a real app
                }
            },
            views: {
            	'': {
                	templateUrl: 'layout.html',
                },
            	'header@root': {
                	template: '<h1>header View<span ng-if="user"><button ng-click="logout()">logout</button></span><span ng-if="!user"><button ng-click="login()">login</button></span></h1>',
                    controller: function($scope, $state, user, userService) {
                    	$scope.user = user;
                        $scope.login = function() {
                        	$state.go('login');
                        };
                        $scope.logout = function() {
                        	userService.logout();
                            $state.go('root.home', {}, {reload: true});
                        };
                    }
            	},
                'footer@root': {
                    template: '<p>footer view</p>'
                }
            }
        })
    	.state('root.home', {
            url: '/',
            views: {
                'content': {
                    template: 'Hello at home'
                }
            }
        })
        .state('root.about', {
            url: '/about',
            views: {
                'content': {
                    template: 'about view'
                }
            }
    	})
        .state('root.restricted', {
            url: '/restricted',
            resolve: {
            	auth: function(userService, $q, $timeout) {
                
                	var deferred = $q.defer();
                	/* //with an async
                    return UserService.load().then(function(user){
                      if (permissionService.can(user, {goTo: state})) {
                        return deferred.resolve({});
                      } else {
                        return deferred.reject({redirectTo: 'some_other_state'});
                      }
                    }*/
                    
                   $timeout(function() {
                        if ( angular.isUndefined(userService.user) ) {
                            return deferred.reject({redirectTo: 'login'});
                        }
                        else {
                            return deferred.resolve(userService.user);
                        }
                    });
                    
                    return deferred.promise;
                }
            },
            views: {
                'content': {
                    template: 'this is only visible after login. Hello {{user}}!',
                    controller: function($scope, auth) {
                    	$scope.user = auth.username;
                    }
                }
            }
    	})
        .state('login', {
            url: '/login',
            templateUrl: 'views/login.html',
            controller: function($scope, $state, userService) {
            	$scope.login = function(cred) {
                	var user = userService.login(cred);
                    
                    if (angular.isUndefined(user)) {
                    	alert('username or password incorrect.')
                    }
                    else {
                    	$state.go('root.restricted');
                    }
                };
            }
        });
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.js"></script>

<div ng-app="demoApp">
    <a ui-sref="root.home" href="#">home</a>
    <a ui-sref="root.about" href="#">about</a>
    <a ui-sref="root.restricted" href="#">restricted page</a>
    
    <div ui-view>
    </div>
    
    <script type="text/ng-template" id="views/login.html">
    	<h1>Login</h1>
        <p>Try testUser and 1234 as credentials</p>
        <label>Username</label><input ng-model="userCred.username"/>
        <label>Password</label><input type="password" ng-model="userCred.password"/>
        <button ng-click="login(userCred)">login</button>
    </script>
    
    <script type="text/ng-template" id="layout.html">
    	<div>
            <div ui-view="header"></div>
            <div ui-view="content"></div>
            <div ui-view="footer"></div>
    	</div>
    </script>
</div>

Solution 2:

app.config(['$stateProvider','$urlRouterProvider',
  function($stateProvider,   $urlRouterProvider) {  
    $urlRouterProvider.otherwise('/login');
    $stateProvider.state('grid', {
      url: '/grid',
      templateUrl: 'resources/html/grid.html',
      controller: 'gridCtrl'
    })
    .state('chDetail', {
      url: "/chDetail/:chId",
      templateUrl: "resources/html/chDetail.html",
      controller: 'chDetailCtrl'
    })
    .state('login', { 
      url: "/login",
      controller: 'loginCtrl',
      views: {
        '': {
          templateUrl: 'resources/html/login.html'
        },
        'login-only@login': {
          templateUrl: 'resources/html/other-html.html'
        }
      }
    });
  }
])
.controller('gridCtrl', ['$scope', function($scope){
  $scope.grid =[];
}]);

I've altered it slightly. To get what you want, use views.

Then your extra bit of code would just be another ui-view, just a named one:

<div ui-view="login-only"></div>

It would only appear on the 'login' state, since you specifically target it via it's name (login-only@login).

You can read more about it at the Multiple Named Views on the ui-router wiki help pages at github.


Solution 3:

very basically you can use $state for get current state like:

module.exports = function Controller($state, $scope)

$scope.currentState = $state.current;

then in your html

<p ng-if="currentState !='login'" ng-include="'${footer}'"></p>

but nested ui-router logic could be more useful.


Post a Comment for "AngularJS UI-Router + State Help Needed"