在角度ui-router中使用带有$stateChangeStart到state和fromState的$state方法

时间:2020-12-30 19:40:29

I'm writing a handler for $stateChangeStart:

我正在为$stateChangeStart编写一个处理程序:

var stateChangeStartHandler = function(e, toState, toParams, fromState, fromParams) {
    if (toState.includes('internal') && !$cookies.MySession) {
        e.preventDefault();
        // Some login stuff.
    }
};

$rootScope.$on('$stateChangeStart', stateChangeStartHandler);

toState does not have the includes method. Should I be doing something different, or is there a way to do what I'm trying to do?

toState没有包含方法。我应该做一些不同的事情,还是有办法做我想做的事情?

Also, when //some login stuff includes a $state.go(...), I get an infinite loop. What might cause that?

此外,当//一些登录信息包括一个$ status .go(…),我得到一个无限循环。这可能会导致什么?


Here's a more complete example demonstrating what we eventually got to work:

这里有一个更完整的例子来说明我们最终要做什么:

angular.module('test', ['ui.router', 'ngCookies'])
.config(['$stateProvider', '$cookiesProvider', function($stateProvider, $cookiesProvider) {

    $stateProvider
    .state('public', {
        abstract: true
    })
    .state('public.login', {
        url: '/login'
    })
    .state('tool', {
        abstract: true
    })
    .state('tool.suggestions', {
        url: '/suggestions'
    });

}])
.run(['$state', '$cookies', '$rootScope', function($state, $cookies, $rootScope) {
    $rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {

        if (toState.name.indexOf('tool') > -1 && !$cookies.Session) {
            // If logged out and transitioning to a logged in page:
            e.preventDefault();
            $state.go('public.login');
        } else if (toState.name.indexOf('public') > -1 && $cookies.Session) {
            // If logged in and transitioning to a logged out page:
            e.preventDefault();
            $state.go('tool.suggestions');
        };
    });
});

I don't like using indexOf to search for a particular state in the toState. It feels naive. I'm not sure why toState and fromState couldn't be an instance of the $state service, or why the $state service couldn't accept a state configuration override in its methods.

我不喜欢使用indexOf来搜索toState中的特定状态。感觉幼稚。我不知道为什么toState和fromState不能是$state服务的实例,或者为什么$state服务不能在其方法中接受状态配置覆盖。

The infinite looping was caused by a mistake on our part. I don't love this, so I'm still looking for better answers.

无限循环是由我们的一个错误引起的。我不喜欢这个,所以我还在寻找更好的答案。

1 个解决方案

#1


66  

Suggestion 1

When you add an object to $stateProvider.state that object is then passed with the state. So you can add additional properties which you can read later on when needed.

当您向$stateProvider添加对象时。然后声明对象与状态一起传递。因此,您可以添加其他属性,稍后在需要时可以读取这些属性。

Example route configuration

例子路由配置

$stateProvider
.state('public', {
    abstract: true,
    module: 'public'
})
.state('public.login', {
    url: '/login',
    module: 'public'
})
.state('tool', {
    abstract: true,
    module: 'private'
})
.state('tool.suggestions', {
    url: '/suggestions',
    module: 'private'
});

The $stateChangeStart event gives you acces to the toState and fromState objects. These state objects will contain the configuration properties.

$stateChangeStart事件使您能够访问toState和fromState对象。这些状态对象将包含配置属性。

Example check for the custom module property

示例检查自定义模块属性

$rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {
    if (toState.module === 'private' && !$cookies.Session) {
        // If logged out and transitioning to a logged in page:
        e.preventDefault();
        $state.go('public.login');
    } else if (toState.module === 'public' && $cookies.Session) {
        // If logged in and transitioning to a logged out page:
        e.preventDefault();
        $state.go('tool.suggestions');
    };
});

I didn't change the logic of the cookies because I think that is out of scope for your question.

我没有改变饼干的逻辑因为我认为这超出了你的问题范围。

Suggestion 2

You can create a Helper to get you this to work more modular.

您可以创建一个助手使您的工作更加模块化。

Value publicStates

价值publicStates

myApp.value('publicStates', function(){
    return {
      module: 'public',
      routes: [{
        name: 'login', 
        config: { 
          url: '/login'
        }
      }]
    };
});

Value privateStates

价值privateStates

myApp.value('privateStates', function(){
    return {
      module: 'private',
      routes: [{
        name: 'suggestions', 
        config: { 
          url: '/suggestions'
        }
      }]
    };
});

The Helper

助手

myApp.provider('stateshelperConfig', function () {
  this.config = {
    // These are the properties we need to set
    // $stateProvider: undefined
    process: function (stateConfigs){
      var module = stateConfigs.module;
      $stateProvider = this.$stateProvider;
      $stateProvider.state(module, {
        abstract: true,
        module: module
      });
      angular.forEach(stateConfigs, function (route){
        route.config.module = module;
        $stateProvider.state(module + route.name, route.config);
      });
    }
  };

  this.$get = function () {
    return {
      config: this.config
    };
  };
});

Now you can use the helper to add the state configuration to your state configuration.

现在可以使用helper将状态配置添加到状态配置中。

myApp.config(['$stateProvider', '$urlRouterProvider', 
    'stateshelperConfigProvider', 'publicStates', 'privateStates',
  function ($stateProvider, $urlRouterProvider, helper, publicStates, privateStates) {
    helper.config.$stateProvider = $stateProvider;
    helper.process(publicStates);
    helper.process(privateStates);
}]);

This way you can abstract the repeated code, and come up with a more modular solution.

通过这种方式,您可以抽象重复的代码,并提出一个更模块化的解决方案。

Note: the code above isn't tested

注意:上面的代码没有经过测试。

#1


66  

Suggestion 1

When you add an object to $stateProvider.state that object is then passed with the state. So you can add additional properties which you can read later on when needed.

当您向$stateProvider添加对象时。然后声明对象与状态一起传递。因此,您可以添加其他属性,稍后在需要时可以读取这些属性。

Example route configuration

例子路由配置

$stateProvider
.state('public', {
    abstract: true,
    module: 'public'
})
.state('public.login', {
    url: '/login',
    module: 'public'
})
.state('tool', {
    abstract: true,
    module: 'private'
})
.state('tool.suggestions', {
    url: '/suggestions',
    module: 'private'
});

The $stateChangeStart event gives you acces to the toState and fromState objects. These state objects will contain the configuration properties.

$stateChangeStart事件使您能够访问toState和fromState对象。这些状态对象将包含配置属性。

Example check for the custom module property

示例检查自定义模块属性

$rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {
    if (toState.module === 'private' && !$cookies.Session) {
        // If logged out and transitioning to a logged in page:
        e.preventDefault();
        $state.go('public.login');
    } else if (toState.module === 'public' && $cookies.Session) {
        // If logged in and transitioning to a logged out page:
        e.preventDefault();
        $state.go('tool.suggestions');
    };
});

I didn't change the logic of the cookies because I think that is out of scope for your question.

我没有改变饼干的逻辑因为我认为这超出了你的问题范围。

Suggestion 2

You can create a Helper to get you this to work more modular.

您可以创建一个助手使您的工作更加模块化。

Value publicStates

价值publicStates

myApp.value('publicStates', function(){
    return {
      module: 'public',
      routes: [{
        name: 'login', 
        config: { 
          url: '/login'
        }
      }]
    };
});

Value privateStates

价值privateStates

myApp.value('privateStates', function(){
    return {
      module: 'private',
      routes: [{
        name: 'suggestions', 
        config: { 
          url: '/suggestions'
        }
      }]
    };
});

The Helper

助手

myApp.provider('stateshelperConfig', function () {
  this.config = {
    // These are the properties we need to set
    // $stateProvider: undefined
    process: function (stateConfigs){
      var module = stateConfigs.module;
      $stateProvider = this.$stateProvider;
      $stateProvider.state(module, {
        abstract: true,
        module: module
      });
      angular.forEach(stateConfigs, function (route){
        route.config.module = module;
        $stateProvider.state(module + route.name, route.config);
      });
    }
  };

  this.$get = function () {
    return {
      config: this.config
    };
  };
});

Now you can use the helper to add the state configuration to your state configuration.

现在可以使用helper将状态配置添加到状态配置中。

myApp.config(['$stateProvider', '$urlRouterProvider', 
    'stateshelperConfigProvider', 'publicStates', 'privateStates',
  function ($stateProvider, $urlRouterProvider, helper, publicStates, privateStates) {
    helper.config.$stateProvider = $stateProvider;
    helper.process(publicStates);
    helper.process(privateStates);
}]);

This way you can abstract the repeated code, and come up with a more modular solution.

通过这种方式,您可以抽象重复的代码,并提出一个更模块化的解决方案。

Note: the code above isn't tested

注意:上面的代码没有经过测试。