2

I'm new to angular and I'm trying to use angular ui router. When I navigate to / I get this abstract state as my $state.current: Object {name: "", url: "^", views: null, abstract: true}. Is there anyway around this so that my current state is files? Here is my code:

(function() {
    'use strict';

    angular.module('carton', [
        'ui.router',
        'carton.controllers',
        'carton.services',
        'carton.directives'
    ]).
    config([
        '$stateProvider',
        '$urlRouterProvider',
        function(
            $stateProvider,
            $urlRouterProvider
        ) {
            $urlRouterProvider.otherwise('/');
            $stateProvider.
            state('files', {
                url: '/',
                templateUrl: 'partials/files.html',
                //controller: 'FilesCtrl'
                access: {
                    isFree: false
                }
            }).

            state('login', {
                url: '/login',
                templateUrl: 'partials/login.html',
                controller: 'loginCtrl',
                access: {
                    isFree: true
                }
            }).

            state('register', {
                url: '/register',
                templateUrl: 'partials/register.html',
                //controller: 'RegisterCtrl'
                access: {
                    isFree: true
                }
            });

        }
    ])

    .run(['$rootScope', '$state', 'UserService',
        function($root, $state, userSrv) {
            $root.$on(
                '$locationChangeSuccess',
                function(event) {
                    console.log($state.current);
                    if (!$state.current.access.isFree && !userSrv.isLogged) {
                        $state.go('login');
                    }
                }
            )
        }
    ]);
})();
Mark Berger
  • 117
  • 1
  • 8

2 Answers2

2

I created a plunker, which should show how to. There are 2 main parts of that solution described below.

We can use some special settings on state definition, BUT they have to be nested in the data object. See the:

Attach Custom Data to State Objects

Adjusted state def would be:

state('files', { 
  ...
  data: {           // here we do nest the custom setting into "data"
    access: {
      isFree: false
    }
  }
})

.state('login', {
  ...
  data: {
    access: {
      isFree: true
    }
  }
})

Also, the more suitable event to listen would be $rootScope.$on('$stateChangeStart', ... Here is an example how to do that:

this could be the implementation in our case:

.run(['$rootScope', '$state', 'UserService',
    function($root, $state, userSrv) {

      $root.$on('$stateChangeStart', function(event, toState
                           , toParams, fromState, fromParams) {

        var isLoginState = toState.name === "login";
        if (isLoginState) {
          return;
        }

        var shouldRequireLogin = !userSrv.isLogged
                    && !toState.data.access.isFree;
        if (shouldRequireLogin) {

          event.preventDefault()
          $state.go('login');
        }
      })
    }
])

There is a working example (register and login available always, files only if logged-on)

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
0

Try this, It always worked for me, Without abstract state didn't work for my requirement, so i always used an abstract state as parent state

$stateProvider.
        state('files', {
            url: '/',
            abstract: true,
            views: {
               "containerView": {
                  template: "<div ng-view=""></div>" 
                            //this ng-view loads your template 'files.html'
               }
            }
         }).
         state('files.list', {
            templateUrl: 'partials/files.html',
            //controller: 'FilesCtrl'
            access: {
                isFree: false
            }
        })

EDIT: This is from my working project

$stateProvider
            .state('classes', {
                url: '/classes',
                abstract: true,
                views: {
                    "containerView": {
                        templateUrl: 'views/desktop/classes/index.html'
                    }
                }
            .state('classes.list', {
                url: '/',
                controller: "ClassListCtrl",
                templateUrl: 'views/desktop/classes/list.html'
            })

Inside index.html i just write <div ng-view=""></div>

Vamsi
  • 9,510
  • 6
  • 38
  • 46