使用 UI-Router 在用户转换到父状态时将用户引导到子状态

IT技术 javascript angularjs angular-ui-router angular-ui
2021-02-23 12:42:05

考虑以下:

.state('manager.staffList', {url:'^/staff?alpha', templateUrl: 'views/staff.list.html', data:{activeMenu: 'staff'}, controller: 'staffListCtrl'})
.state('manager.staffDetail', {url:'^/staff/{id}' , templateUrl: 'views/staff.html', data:{activeMenu: 'staff'}, controller: 'staffDetailsCtrl'})
  .state('manager.staffDetail.view', {url:'/view',  templateUrl: 'views/staff.details.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.schedule', {url:'/schedule', templateUrl:'views/staff.view.schedule.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.history', {url:'/history' , templateUrl:'views/staff.view.history.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.log', {url:'/log', templateUrl:'views/staff.view.log.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.files', {url:'/files', templateUrl:'views/staff.view.files.html', data:{activeMenu: 'staff'}})
  .state('manager.staffDetail.edit', {url:'/edit',  templateUrl: 'views/staff.edit.html', data:{activeMenu: 'staff'}})

如果我去domain.com/staff/1234/view,我如何默认为manager.staffDetail.view.schedule孩子状态?

6个回答
  1. 首先,向 的'manager.staffDetail.view'状态添加一个属性abstract:true这不是必需的,但您想设置它,因为您永远不会直接进入这个状态,您总是会进入它的子状态之一。

  2. 然后执行以下操作之一

    • 'manager.staffDetail.view.schedule'状态一个空 URL这将使其匹配与父状态 url 相同的 url,因为它不会向父 url 附加任何内容。

      .state('manager.staffDetail.view.schedule', {url:'', ...

    • 或者如果你想保持默认子路由的 url 不变,那么在你的 module.config 中设置一个重定向此处的代码会将 的任何位置重定向'/staff/{id}/view'到 的位置'/staff/{id}/view/schedule'

      $urlRouterProvider.when('/staff/{id}/view', '/staff/{id}/view/schedule');

对于$urlRouterProvider重定向,我在使用带有 的链接时出错ui-sref="manager.staffDetail.view",因此我需要abstract: true从父状态声明中删除
2021-05-01 12:42:05
第二个选项不适用于内部 ui-sref 链接(它不会转到子状态)
2021-05-07 12:42:05

要设置默认子视图,请查看此示例单击Route 1加载默认状态route1.list

// For any unmatched url, send to /route1
$stateProvider
  .state('route1', {
      url: "/route1",
      abstract:true ,
      templateUrl: "route1.html"
  })
  .state('route1.list', {
      url: '',
      templateUrl: "route1.list.html",
      controller: function($scope){
        $scope.items = ["A", "List", "Of", "Items"];
      }
  })
  .state('route1.desc', {
      url: "/desc",
      templateUrl: "route1.desc.html",
      controller: function($scope){
        $scope.items = [];
      }
  })
  .state('route2', {
    url: "/route2",
    templateUrl: "route2.html"
  })
  .state('route2.list', {
    url: "/list",
    templateUrl: "route2.list.html",
    controller: function($scope){
      $scope.things = ["A", "Set", "Of", "Things"];
    }
  })
您必须使用 href="/abstractroute" 链接到父级
2021-04-21 12:42:05
谁能向我解释为什么route1这个例子中状态需要一个 templateUrl?或者更一般地说,为什么一个abstract:true国家需要一个模板?
2021-04-30 12:42:05
如果我们想在 ui-sref 中使用父状态,这是一个大问题
2021-05-11 12:42:05
如果route1.desc没有 url,您仍然可以使用 访问它$state.go,但route1.list默认情况下会在/route1:)上加载如果您不想通过 url 直接访问状态,这很有用
2021-05-15 12:42:05
孩子的父母应该有一个 abstract:true
2021-05-15 12:42:05

我遇到了同样的问题,发现这个解决方案有效:

https://github.com/angular-ui/ui-router/issues/948#issuecomment-75342784

这是从@christopherthielen 在 github 上引用的

“现在,不要声明你的状态抽象,并使用这个秘诀:”

 app.run($rootScope, $state) {
    $rootScope.$on('$stateChangeStart', function(evt, to, params) {
      if (to.redirectTo) {
        evt.preventDefault();
        $state.go(to.redirectTo, params)
      }
    });
  }

  $stateProvider.state('parent' , {
      url: "/parent",
      templateUrl: "parent.html",
      redirectTo: 'parent.child'
  });

  $stateProvider.state('parent.child' , {
      url: "/child",
      templateUrl: "child.html"
  });

以下是该过程如何工作的细分:

  1. 用户导航到状态“父”
  2. “$stateChangeStart”事件被触发
  3. “$stateChangeStart”的侦听器捕获事件并将“toState”(即“父”)和“事件”传递给处理函数
  4. 处理函数检查是否在“toState”上设置了“redirectTo”。
  5. 如果未设置“redirectTo”,则不会发生任何事情,用户将继续进入“toState”状态。
  6. 如果设置了“redirectTo”,则事件被取消(event.preventDefault)并且 $state.go(toState.redirectTo) 将它们发送到“redirectTo”中指定的状态(即“parent.child”)。
  7. “$stateChangeStart”事件再次被触发,但这次“toState”==“parent.child”并且“redirectTo”选项没有设置,所以它继续“toState”。
嗨 Kishore - 我更新了答案以解释它是如何工作的。除非您在“redirectTo”选项中明确指定“父”状态,否则不会出现无限循环。
2021-04-24 12:42:05
任何人都可以解释这一点。这不会变成无限循环吗?
2021-05-09 12:42:05
我试过这个,但不幸的是这对我不起作用。我正在使用 ui-router v0.3.1
2021-05-13 12:42:05

很晚了,但我认为您可以“重定向”到您想要的状态。

.state('manager.staffDetail.view', {
    url:'/view',
    templateUrl: 'views/staff.details.html',
    controller: 'YourController'
})

app.controller('YourController', ['$state',
function($state) {
    $state.go('manager.staffDetail.view.schedule');
}]);

简而言之,您可以在状态配置中直接编写控制器。

我试过了,但它会加倍加载控制器、解析和 onStateChange 的任何内容。我只使用 $urlRouterProvider.when('/app/service', '/app/service/list')
2021-04-25 12:42:05
如果您的导航具有父 sref,则它不适用于后续点击 - 仅适用于初始控制器加载。
2021-05-07 12:42:05
由于子状态也会再次调用父状态,因为我们将再次重定向到 child.
2021-05-13 12:42:05

我将“manager.staffDetial.view”更改为抽象状态,并将默认子状态的 url 保留为空白“”

// Staff
.state('manager.staffList',    {url:'^/staff?alpha',      templateUrl: 'views/staff.list.html', data:{activeMenu: 'staff'}, controller: 'staffListCtrl'})
.state('manager.staffDetail',   {url:'^/staff/{id}', templateUrl: 'views/staff.html', data:{activeMenu: 'staff'}, controller: 'staffDetailsCtrl'})
.state('manager.staffDetail.view',   {url:'/view', abstract: true, templateUrl: 'views/staff.details.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.schedule', {url:'', templateUrl:'views/staff.view.schedule.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.history', {url:'/history', templateUrl:'views/staff.view.history.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.log', {url:'/log', templateUrl:'views/staff.view.log.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.files', {url:'/files', templateUrl:'views/staff.view.files.html', data:{activeMenu: 'staff'}})
.state('manager.staffDetail.edit',   {url:'/edit',  templateUrl: 'views/staff.edit.html', data:{activeMenu: 'staff'}})
是的,你说得对,我是用手机写的答案... :PI 已经清理了答案,我希望现在更有意义。此外,我注意到,在谷歌,如果我搜索UI路由器这个线程是第四个结果,所以它重要的是我们拥有它很清楚。
2021-04-21 12:42:05
好像你所做的一切,我都提到过(虽然,是的,我的例子中的代码是不必要的)。我:“……你应该把它设置成抽象状态。” 你:“我把‘manager.staffDetial.view’改成了抽象状态……” 我:“或者一个不同的选择是给 schedule 一个空的 URL。” 你:“......并将我的默认子状态的 url 保留为空白”。不过,真的没有什么不好的感觉,我很高兴你明白了。
2021-04-27 12:42:05
抱歉,您的回答令人困惑,而且没有重点。阅读您的解释后,我看到您给出了单独的选项,最后,如果我将您的第一个和最后一个选项结合起来,而忽略了中间的建议,我就会有一个解决方案。我想我知道你要去哪里,但我不确定如果我将你的标记为答案,它会帮助下一位读者。如果您想编辑您的答案并清除您的答案,我很乐意为您提供答案。
2021-04-29 12:42:05
我不确定你是否知道“确切地”这个词是什么意思。但是,您的代码示例使用了 routeProvider 方法。我选择根本不使用它,而是将解决方案保留在状态管理器中。这样代码保持干净,不会添加任何不必要的额外代码行。你的例子是一个可能的答案,但不是最可接受的答案。
2021-05-07 12:42:05
所以你基本上完全按照我的建议做了……那为什么不给我的答案正确的复选标记呢?所以我可以获得代表点数。
2021-05-11 12:42:05