ui-router和登录url返回状态

时间:2015-04-07 21:34:45

标签: angularjs angular-ui-router

这是一个复杂的问题。 我试图在用户尝试访问需要授权的页面时创建一个returnState。

所以,我在状态对象上创建了一些如下所示的数据:

$stateProvider.state('account', {
    url: '/account',
    templateUrl: '/app/account/index.tpl.html',
    controller: 'AccountController',
    controllerAs: 'controller',
    data: {
        requireLogin: true,
        state: 'account' // tells the page to redirect here if not logged in
    }
});

然后我有一些代码在stateChangeStart上运行:

.run(['$rootScope', '$state', 'AccountService', function ($rootScope, $state, account) {

    // On state change
    $rootScope.$on('$stateChangeStart', function (event, toState) {

        var data = toState.data; // Get our state data
        var requireLogin = typeof data === 'undefined' ? false : data.requireLogin; // Check to see if we have any data and if so, check to see if we need login rights
        var user = account.current() // Get our current user

        // If we require login rights and we are not authenticated
        if (requireLogin && !user.authenticated) {

            // Get our current state
            var state = data.state || '';

            // Stop processing
            event.preventDefault();

            // redirect to the login page and pass the state parameter
            $state.transitionTo('login', { returnState: state });
        }
    });
}]);

然后在我的loginController上我有这个功能:

self.loginUser = function () {

    // Login
    self.login = service.login(self.model);

    // If we login properly
    self.login.promise.then(function (response) {

        // If we have a return Url
        if (returnState) {

            // Go to that url
            $state.go(returnState);
        } else {

            // Otherwise, Redirect to the home page
            $state.go('home');
        }
    });
};

我展示的例子完美无缺。但现在我发现我有更复杂的需求。 我有另一组状态:

$stateProvider.state('designer', {
    url: '/:sport/designer',
    abstract: true,
    templateUrl: '/app/designer/designer.tpl.html',
    controller: 'DesignerController',
    controllerAs: 'controller'
}).state('designer.team', {
    url: '',
    templateUrl: '/app/designer/team.tpl.html'
}).state('designer.kit', {
    url: '/kit',
    templateUrl: '/app/designer/kit.tpl.html'
}).state('designer.design', {
    url: '/design',
    templateUrl: '/app/designer/design.tpl.html'
}).state('designer.refine', {
    url: '/refine',
    templateUrl: '/app/designer/refine.tpl.html'
}).state('designer.order', {
    url: '/order',
    templateUrl: '/app/designer/order.tpl.html'
}).state('designer.save', {
    url: '/save',
    templateUrl: '/app/designer/save.tpl.html',
    data: {
        requireLogin: true
    }
});

正如你所看到的,这个状态和一些孩子以及最后一个状态(保存)需要用户登录。因为状态继承了父母的参数,我应该能够做到这样的事情:

state: 'designer.save({ sport: :sport })'

但我收到错误声明:

  
    

错误:无法解析' desginer.save({sport ::运动})'来自州'登录'

  

现在我假设这是因为:运动不是作为一个字符串传递,但我已经尝试了很多,我无法让它工作。 有没有更好的方法来处理路线?

我确实尝试使用stateChangeStart函数来获取我们正在移动的状态,但我似乎无法访问它。

3 个答案:

答案 0 :(得分:1)

首先,如果我们查看the docs,我们可以看到$state.go接受以下参数:

  • 绝对州名
  • 参数
  • 选项

我无法看到任何地方提到将参数直接放入州名称是骗取的。所以我们有错误消息的原因。 'designer.save({ sport: :sport })' 不是正确的绝对州名。

  

因为州继承了父母的参数

这意味着您不仅可以访问它们,还可以在某些情况下自动传递它们:

  

任何未指定的参数都将从当前继承   定义的参数。例如,这允许进入兄弟状态   共享在父状态中指定的参数。参数   继承只适用于共同的祖先状态,即。   过渡到兄弟姐妹将获得所有参数   父母,过渡到孩子将获得所有当前参数,   等

因此,只要您处于designer州或其中任何一个州,您就不必提供任何参数。如果你不是,那么你需要找到一种方法将参数作为第二个参数传递给$state.go

答案 1 :(得分:0)

感谢user2847643的建议。我实际上想出了一个更好的处理方法。 首先,我将登录状态修改为:

$stateProvider.state('login', {
    url: '/account/login',
    params: {
        returnState: '',
        returnParams: {}
    },
    views: {

        // the main template will be placed here (relatively named)
        '': {
            templateUrl: 'app/account/login/index.tpl.html'
        },

        // the child views will be defined here (absolutely named)
        'register@login': {
            templateUrl: 'app/account/login/register.tpl.html',
            controller: 'RegisterController',
            controllerAs: 'controller'
        },

        // for column two, we'll define a separate controller 
        'login@login': {
            templateUrl: 'app/account/login/login.tpl.html',
            controller: 'LoginController',
            controllerAs: 'controller'
        }
    }
});

如您所见,这接受两个可选参数。 然后我将登录功能修改为:

self.loginUser = function () {

    // Login
    self.login = service.login(self.model);

    // If we login properly
    self.login.promise.then(function (response) {

        console.log(returnState);
        console.log(returnParams);

        // If we have a return Url
        if (returnState) {

            // Go to that url
            $state.go(returnState, returnParams);
        } else {

            // Otherwise, Redirect to the home page
            $state.go('home');
        }
    });
};

现在正确调用 $ state.go 函数传递状态和参数(或空对象)。

我实际上把我的逻辑用于处理我之前展示的 stateChangeStart 绑定中的returnStates,所以现在看起来像这样:

$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {

    var data = toState.data; // Get our state data
    var requireLogin = typeof data === 'undefined' ? false : data.requireLogin; // Check to see if we have any data and if so, check to see if we need login rights
    var user = account.current() // Get our current user

    // If we require login rights and we are not authenticated
    if (requireLogin && !user.authenticated) {

        // Get our current state
        var name = toState.name;
        var params = toParams;

        // If our state is the login page (i.e. we accessed it directly)
        if (name === 'login') {

            // Set our state to the homepage
            name = 'home';
            toParams = {};
        }

        // Stop processing
        event.preventDefault();

        // redirect to the login page and pass the state parameter
        $state.transitionTo('login', { returnState: name, returnParams: params });
    }
});

我们有它。

答案 2 :(得分:0)

感谢r3plica这篇文章。我面临的问题很少,并以下列方式解决。如果我错了,有人可以纠正我。

  1. 你应该使用ui-router最新版本,旧版本不支持params。我使用的是0.2.13。
  2. 在控制器中,您需要将参数读取为$ state.go($ stateParams.returnState,$ stateParams.returnParams)
  3. 在$ stateChangeStart事件中,您还需要从State,fromParams传递参数。这用于检查fromState是否未登录,因此您一次又一次地跳过重新加载登录页面。

    $ rootScope。$ on('$ stateChangeStart',function(event,toState,toParams,fromState,fromParams){        // var restrictedPage = $ .inArray($ location.path(),['/ landing','/ list','/ landing / users']);

        var data = toState.data;
        if(typeof toState.data !== 'undefined' && fromState.name !== 'login'){......}
       }