【问题标题】:`ui-router` $stateParams vs. $state.params`ui-router` $stateParams 与 $state.params
【发布时间】:2014-05-29 16:05:33
【问题描述】:

使用ui-router,可以将$state$stateParams 注入控制器以访问URL 中的参数。但是,通过$stateParams访问参数只会暴露属于访问它的控制器所管理的状态及其父状态的参数,而$state.params拥有所有参数,包括任何子状态中的参数。

给定以下代码,如果我们直接加载 URL http://path/1/paramA/paramB,控制器加载时是这样的:

$stateProvider.state('a', {
     url: 'path/:id/:anotherParam/',
     controller: 'ACtrl',
  });

$stateProvider.state('a.b', {
     url: '/:yetAnotherParam',
     controller: 'ABCtrl',
  });

module.controller('ACtrl', function($stateParams, $state) {
   $state.params; // has id, anotherParam, and yetAnotherParam
   $stateParams;  // has id and anotherParam
}

module.controller('ABCtrl', function($stateParams, $state) {
   $state.params; // has id, anotherParam, and yetAnotherParam
   $stateParams;  // has id, anotherParam, and yetAnotherParam
}

问题是,为什么会有差异?是否有关于何时以及为什么应该使用或避免使用其中任何一种的最佳实践指南?

【问题讨论】:

  • 如此出色的说明问题 - 谢谢你告诉我什至我想问的问题!

标签: angularjs angular-ui-router


【解决方案1】:

文档在这里重申了您的发现:https://github.com/angular-ui/ui-router/wiki/URL-Routing#stateparams-service

如果我没记错的话,$stateParams 是比原来的$state.params 更晚引入的,而且似乎是一个简单的辅助注入器,可以避免连续写入$state.params

我怀疑是否有任何最佳实践指南,但上下文对我来说更胜一筹。如果您只想访问接收到 url 的参数,请使用$stateParams。如果您想了解有关状态本身的更复杂的信息,请使用$state

【讨论】:

  • 我发现自己在ACtrl 中使用了$state.params,因为我想检查是否设置了yetAnotherParam。所以如果不是,我可以做点什么。我不会详细介绍那个 something 的内容,因为它可以保证它自己的问题。但是,我觉得我可能正在通过检查子状态引入的参数进行hack,并且当前状态无法通过$stateParams 识别该参数。从那以后,我找到了另一种方法。
  • 其实,两者的区别不仅仅是上下文的问题。 $stateParams 捕获 $state 认为适用于该状态的基于 url 的参数,即使其子状态包含更多参数。 $state.params 似乎捕获了您所处的 当前状态 的所有 url + 基于非 url 的参数。如果您处于状态 parent.child,那么 parentController 中的 $stateParams 将评估 url - 基于 parent 的参数,但不是 parent.child 的参数。见this issue
  • 另一方面,$stateParams 可以保留自定义对象、类型等,而 $state.params 将“将自定义对象转换为普通对象”。
  • $stateParams 在解析中有效,而 $state.params 不正确(未显示尚未解析的状态的参数)
  • 我发现范围可以$watch $state.params,但不能$stateParams。我不知道为什么。
【解决方案2】:

使用$state.params 的另一个原因是用于非基于 URL 的状态,(在我看来)它的文档很少而且非常强大。

我刚刚在谷歌搜索如何传递状态时发现了这一点,而不必在 URL 和 SO 上的 answered a question elsewhere 中公开它。

基本上,它允许这种语法:

<a ui-sref="toState(thingy)" class="list-group-item" ng-repeat="thingy in thingies">{{ thingy.referer }}</a>

【讨论】:

  • 嗨,bbrown,不知怎的,我不能让它工作,你有一个工作的例子吗?
【解决方案3】:

编辑:这个答案对于版本0.2.10 是正确的。正如@Alexander Vasilyev 指出的那样,它在0.2.14 版本中不起作用。

使用$state.params 的另一个原因是当您需要像这样提取查询参数时:

$stateProvider.state('a', {
  url: 'path/:id/:anotherParam/?yetAnotherParam',
  controller: 'ACtrl',
});

module.controller('ACtrl', function($stateParams, $state) {
  $state.params; // has id, anotherParam, and yetAnotherParam
  $stateParams;  // has id and anotherParam
}

【讨论】:

【解决方案4】:

这两者之间有很多不同之处。但是在实际工作时,我发现使用$state.params 更好。当您使用越来越多的参数时,在$stateParams 中维护可能会令人困惑。如果我们使用多个不是 URL 的参数,$state 非常有用

 .state('shopping-request', {
      url: '/shopping-request/{cartId}',
      data: {requireLogin: true},
      params : {role: null},
      views: {
        '': {templateUrl: 'views/templates/main.tpl.html', controller: "ShoppingRequestCtrl"},
        'body@shopping-request': {templateUrl: 'views/shops/shopping-request.html'},
        'footer@shopping-request': {templateUrl: 'views/templates/footer.tpl.html'},
        'header@shopping-request': {templateUrl: 'views/templates/header.tpl.html'}
      }
    })

【讨论】:

    【解决方案5】:

    我有一个可以解决某事的根状态。将$state 作为解析参数传递并不能保证$state.params 的可用性。但是使用$stateParams 会。

    var rootState = {
        name: 'root',
        url: '/:stubCompanyId',
        abstract: true,
        ...
    };
    
    // case 1:
    rootState.resolve = {
        authInit: ['AuthenticationService', '$state', function (AuthenticationService, $state) {
            console.log('rootState.resolve', $state.params);
            return AuthenticationService.init($state.params);
        }]
    };
    // output:
    // rootState.resolve Object {}
    
    // case 2:
    rootState.resolve = {
        authInit: ['AuthenticationService', '$stateParams', function (AuthenticationService, $stateParams) {
            console.log('rootState.resolve', $stateParams);
            return AuthenticationService.init($stateParams);
        }]
    };
    // output:
    // rootState.resolve Object {stubCompanyId:...}
    

    使用“angular”:“~1.4.0”、“angular-ui-router”:“~0.2.15”

    【讨论】:

      【解决方案6】:

      在将先前的状态参数从一条路由传递到另一条路由时,我发现一个有趣的现象是 $stateParams 被提升并覆盖了与当前状态参数一起传递的先前路由的状态参数,但使用 $state.params 不会。

      使用$stateParams时:

      var stateParams        = {};
      stateParams.nextParams = $stateParams; //{item_id:123}
      stateParams.next       = $state.current.name;
      
      $state.go('app.login', stateParams);
      //$stateParams.nextParams on app.login is now:
      //{next:'app.details', nextParams:{next:'app.details'}}
      

      使用 $state.params 时:

      var stateParams        = {};
      stateParams.nextParams = $state.params; //{item_id:123}
      stateParams.next       = $state.current.name;
      
      $state.go('app.login', stateParams);
      //$stateParams.nextParams on app.login is now:
      //{next:'app.details', nextParams:{item_id:123}}
      

      【讨论】:

        【解决方案7】:

        本文中的Here 明确说明:$state 服务提供了许多有用的方法来操作状态以及当前状态的相关数据。当前状态参数可在$state 服务的 params 键处访问。 $stateParams 服务返回这个相同的对象。因此,$stateParams 服务严格来说是一种便捷服务,可以快速访问$state 服务上的 params 对象。

        因此,任何控制器都不应该同时注入$state 服务及其便利服务$stateParams。如果注入$state 只是为了访问当前参数,则应重写控制器以注入$stateParams

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-11-20
          • 2016-05-13
          • 2018-06-04
          • 2016-01-08
          • 1970-01-01
          • 2016-10-27
          • 2016-04-28
          • 2016-08-21
          相关资源
          最近更新 更多