ui-router 1.xx在解析期间更改$ transition $ .params()

rav*_*ave 12 angularjs angular-ui-router

尝试迁移angularjs应用程序以使用新版本的angular-ui-router1.0.14,并在尝试更改$stateParams状态的解析时偶然发现问题.

例如,之前(当使用angular-ui-router0.3.2时)修改$stateParams工作如下:

 $stateProvider.state('myState', {
   parent: 'baseState',
   url: '/calendar?firstAvailableDate',
   template: 'calendar.html',
   controller: 'CalendarController',
   controllerAs: 'calendarCtrl',
   resolve: {
     availableDates: ['CalendarService', '$stateParams', function(CalendarService, $stateParams) {
       return CalendarService.getAvailableDates().then(function(response){
          $stateParams.firstAvailableDate = response[0];
          return response;
       });
     }]
   }
 })
Run Code Online (Sandbox Code Playgroud)

问题是firstAvailableDate在解决后填充,我不知道$transition$.params()在使用新版本的angular-ui-router1.0.14 时如何更新解决方案.

我试过,并设法用更新url参数

  1. 射击$state.go('myState', {firstAvailableDate : response[0]})但这会重新加载状态,因此屏幕闪烁

  2. 修改$transition$.treeChanges().to[$transition$.treeChanges().length-1].paramValues.firstAvailableDate = response[0];为实际覆盖参数.在查看了实现之后,我已经完成了这项params()工作$transition$.

虽然这些选项都有效,但它们似乎是黑客而不是书籍实施.

尝试修改解析中的参数时,使用的正确方法是什么?

lin*_*lin 6

具有动态参数的方法:

看一下这个文档:params.paramdeclaration#dynamic。也许这就是您想要的:...a transition still occurs...。

当dynamic为true时,更改参数值将不会导致状态的输入/退出。解析将不会重新获取,也不会重新加载视图。

通常,如果参数值更改,则声明该参数将被重载(输入/退出)的状态。当参数为动态时,过渡仍会发生,但不会导致状态退出/进入。

这对于在构建UI时很有用,在该UI中,当参数值更改时,组件会自行更新。一种有用的常见方案是搜索/分页/排序。

请注意,您无法将这样的逻辑放入您内部的解决方案中$stateProvider.state。我可以通过使用dynamic参数来防止状态重新加载来做到这一点。不幸的是,dynamic当您尝试$stage.go()在解决方案部分中更新状态(例如,通过使用)时,规则不起作用。因此,我将该逻辑移至控制器中以使其正常工作-DEMO PLNKR。

由于userId是动态参数,因此更改视图后不会再次进入/退出视图。

定义动态参数:

  $stateProvider.state('userlist.detail', {
    url: '/:userId',
    controller: 'userDetail',
    controllerAs: '$ctrl',
    params: {
      userId: {
        value: '',
        dynamic: true
      }
    },
    template: `
        <h3>User {{ $ctrl.user.id }}</h3>

        <h2>{{ $ctrl.user.name }} {{ !$ctrl.user.active ? "(Deactivated)" : "" }}</h2>

        <table>
          <tr><td>Address</td><td>{{ $ctrl.user.address }}</td></tr>
          <tr><td>Phone</td><td>{{ $ctrl.user.phone }}</td></tr>
          <tr><td>Email</td><td>{{ $ctrl.user.email }}</td></tr>
          <tr><td>Company</td><td>{{ $ctrl.user.company }}</td></tr>
          <tr><td>Age</td><td>{{ $ctrl.user.age }}</td></tr>
        </table>
    `
  });
Run Code Online (Sandbox Code Playgroud)

您的控制器:

app.controller('userDetail', function ($transition$, $state, UserService, users) {

  let $ctrl = this;

  this.uiOnParamsChanged = (newParams) => {

    console.log(newParams);

    if (newParams.userId !== '') {
      $ctrl.user = users.find(user => user.id == newParams.userId);
    }
  };

  this.$onInit = function () {

    console.log($transition$.params());

    if ($transition$.params().userId === '') {
      UserService.list().then(function (result) {
        $state.go('userlist.detail', {userId: result[0].id});
      });
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

通过$transition.on*在路线更改开始时使用钩子来处理新参数:

另一种方法是state在更改状态之前设置正确的参数。但是您已经说过,这是您不想要的。如果我会遇到相同的问题:state在更改视图之前,我将尝试设置正确的参数。

app.run(function (
    $transitions,
    $state,
    CalendarService
) {

    $transitions.onStart({}, function(transition) {
        if (transition.to().name === 'mySate' && transition.params().firstAvailableDate === '') {

            // please check this, I don't know if a "abort" is necessary
            transition.abort();

            return CalendarService.getAvailableDates().then(function(response){
                // Since firstAvailableDate is dynamic 
                // it should be handled as descript in the documents.
                return $state.target('mySate', {firstAvailableDate : response[0]});
            });
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

通过$transition.on*在路由更改上使用钩子来处理新参数,这些钩子通过redirectTo开始

注意:在LAZY解析之前,redirectTo被作为onStart挂钩处理。

这与上面标题“ 在路线更改开始时使用$transition.on*钩子处理新参数 ”附近提供的功能相同,因为redirectTo这也是onStart具有自动处理功能的钩子。

$stateProvider.state('myState', {
    parent: 'baseState',
    url: '/calendar?firstAvailableDate',
    template: 'calendar.html',
    controller: 'CalendarController',
    controllerAs: 'calendarCtrl',
    redirectTo: (trans) => {
        if (trans.params().firstAvailableDate === '') {
            var CalendarService = trans.injector().get('CalendarService');
            return CalendarService.getAvailableDates().then(function(response){
                return { state: 'myState', params: { firstAvailableDate: response[0] }};
            });
        }
    }
});
Run Code Online (Sandbox Code Playgroud)