防止击中子状态ui-router

时间:2015-02-05 15:40:00

标签: javascript angularjs angular-ui-router

以下是我到目前为止ui-router状态:

$stateProvider
  .state('tools', {
    url: '/tools/:tool',
    template: '<div ui-view=""></div>',
    abstract: true,
    onEnter: function ($stateParams, $state, TOOL_TYPES) {
      if (TOOL_TYPES.indexOf($stateParams.tool) === -1) {
        $state.go('error');
      }
    }
  })
  .state('tools.list', {
    url: '',
    templateUrl: 'app/tools/tools.tpl.html',
    controller: 'ToolsController'
  })
  .state('tools.view', {
    url: '/:id/view',
    templateUrl: 'app/tools/partials/tool.tpl.html',
    controller: 'ToolController'
  });

正如您所见,父状态的参数tool只能在TOOL_TYPES数组中。因此,如果tool不可用,我想重定向到错误页面。

实际上,一切都按预期工作,但我得到两个错误:

TypeError: Cannot read property '@' of null

TypeError: Cannot read property '@tools' of null

所以我想,儿童状态已被击中&#39;无论如何。有可能阻止这种情况吗?或者也许还有其他方法可以实现我想要的目标?

1 个答案:

答案 0 :(得分:9)

Angular ui-router's 文档提到当状态变为活动状态时会调用onEnter回调,因此会激活子状态。

要解决此问题,您需要实现两件事:

  1. 创建一个resolve,一旦特定条件不适用于该状态,就会返回被拒绝的承诺。确保被拒绝的承诺与有关要重定向的状态的信息一起传递。

  2. $stateChangeError中创建一个$rootScope事件处理程序,并使用第六个参数,该参数表示您在被拒绝的承诺中传递的信息。使用该信息创建重定向实施。

  3. <强> DEMO

    <强>的Javascript

    angular.module('app', ['ui.router'])
    
      .value('TOOL_TYPES', [
        'tool1', 'tool2', 'tool3'
      ])
    
      .config(function($stateProvider, $urlRouterProvider) {
    
        $stateProvider
    
          .state('error', {
            url: '/error',
            template: 'Error!'
          })
    
          .state('tools', {
            url: '/tools/:tool',
            abstract: true,
            template: '<ui-view></ui-view>',
            resolve: {
              tool_type: function($state, $q, $stateParams, TOOL_TYPES) {
    
                var index = TOOL_TYPES.indexOf($stateParams.tool);
    
                if(index === -1) {
                  return $q.reject({
                    state: 'error'
                  });
                }
    
                return TOOL_TYPES[index];
              }
            }
          })
    
          .state('tools.list', {
            url: '',
            template: 'List of Tools',
            controller: 'ToolsController'
          })
          .state('tools.view', {
            url: '/:id/view',
            template: 'Tool View',
            controller: 'ToolController'
          });
    
      })
    
      .run(function($rootScope, $state) {
        $rootScope.$on('$stateChangeError', function(
          event, toState, toStateParams, 
          fromState, fromStateParams, error) {
    
            if(error && error.state) {
              $state.go(error.state, error.params, error.options);
            }
    
        });
      })
    
      .controller('ToolsController', function() {})
      .controller('ToolController', function() {});