Angular ui-路由器之争

Angular ui-router struggle

好吧,我有这个项目,ui-router 让我很难过。我做了一个 quick Plunker 演示:http://plnkr.co/edit/imEErAtOdEfaMMjMXQfD?p=preview

所以基本上我有一个主视图,index.html,其他顶级视图被注入其中,像这样 operations.index.html。当顶层视图中有多个命名视图时,我的大脑开始疼痛,operations.detail.htmloperations.list.html 被注入 operations.index.html,后者又被注入 index.html .

基本上,我要实现的是以下行为:

  1. 当用户单击导航栏中的 Operations 项时,将显示一个包含空(新)操作的页面。 URL 是 /operations.
  2. 当他们 select 列表中的一个项目时,字段会更新一些数据(数据是通过服务请求的,但为简单起见,我们假设它就在控制器中)。 URL 是 /operations/:id.
  3. 如果他们决定要创建一个新项目,同时编辑当前项目,他们单击列表顶部的 New operation 按钮,URL 将从 /operations/:id 变为至 /operations.
  4. 无论新项目还是旧项目,导航栏中的项目 Operations 都保持活动状态。
  5. 如果用户正在编辑一个项目,它应该在列表中突出显示为活动,如果他们创建一个新项目 — New operation 按钮应该相应地突出显示。

现在,检查一下奇怪的行为:转到 Operations,然后再次单击 Operations 导航栏项。一切都消失了。如果我做 Operations -> select Operation 1 -> select New operation.

也会发生同样的情况

此外,请查看我尝试获取 id 参数的部分:

$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
  if (toParams) {
    if (toParams.id) {
      for (var i = 0; i < vm.operations.length; i++) {
        if (vm.operations[i].id == toParams.id) {
          vm.operation = vm.operations[i];
          break;
        }
      }
    }
  }
});

我不是专家,但看起来太长太复杂了,尤其是对于获取请求参数这样简单的任务。如果我尝试检查状态更改 $stateParams,则对象为空,因此采用此解决方法。如果我尝试篡改 app.js 中的状态,情况会略有不同,但总会出现 Operations 导航栏项目失去其活动状态或其他奇怪的东西之类的错误。

我知道问这样笼统的问题在 SO 中并不常见,但我真的无法理解 ui-router 的概念,我能感觉到我在这里做错了,并且如果能为我指明如何正确使用 ui-router 的正确方向,我将不胜感激。干杯。

the updated plunker

我刚刚使用了这个问答中的技术:

我添加了 redirectTo 设置 (可以是任何状态)

.state('operations', {
      url: '/operations',
      templateUrl: 'operations.index.html',
      controller: 'operationsController as op',
      // here is redirect
      redirectTo: 'operations.new',
 })

并添加了这个 redirector:

app.run(['$rootScope', '$state', function($rootScope, $state) {

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

此外,我删除了当前位于 operationsController.js:

中的重定向
angular.module('uiRouterApp')
  .controller('operationsController', function($state, $stateParams, $rootScope) {
    var vm = this;

    //if ($state.current.name === 'operations') $state.go('operations.new');

以上只是为了保持新状态 - 没有 url。因为解决方案会变得更容易,如果我们只引入 url: '/new':

.state('operations', {
  url: '/operations',
  ..
})
.state('operations.new', {
  //url: '',
  url: '/new',

勾选plunker here

因此,我们通过这种方式为路由赋予了生命。现在是让细节发挥作用的时候了。为了实现它,我们需要更多 - there is another updated plunker

首先,我们将全新controller两个子状态视图:

.state('operations.new', {
  url: '',
  views: {
    'detail': {
      templateUrl: 'operations.detail.html',
      controller: 'detailCtrl as dc',         // here new controller
   ...
})
.state('operations.detail', {
  url: '/:id',
  views: {
    'detail': {
      templateUrl: 'operations.detail.html',
      controller: 'detailCtrl as dc',         // here new controller
    ...

两者可能是同一个控制器,因为我们将根据 $stateParams.id 的内容保留新的或现有的决定。这将是它的实现:

.controller('detailCtrl', function($scope, $state, $stateParams) {
    var op = $scope.op;

    op.operation = {id:op.operations.length + 1};

    if ($stateParams.id) {
      for (var i = 0; i < op.operations.length; i++) {
        if (op.operations[i].id == $stateParams.id) {
          op.operation = op.operations[i];
          break;
        }
      }
    }
})

我们保持原来的方法,并在选择$stateParams.id时设置op.operation。如果不是,我们创建新项目,id 适当递增。

现在我们只是调整父控制器,不保存现有的,只保存新的:

  .controller('operationsController', function($state, $stateParams, $rootScope) {
    var vm = this;

    //if ($state.current.name === 'operations') $state.go('operations.new');

    vm.operation = {};

    /*$rootScope.$on('$stateChangeStart', 
                    function(event, toState, toParams, fromState, fromParams) {
      if (toParams) {
        if (toParams.id) {
          for (var i = 0; i < vm.operations.length; i++) {
            if (vm.operations[i].id == toParams.id) {
              vm.operation = vm.operations[i];
              break;
            }
          }
        }
      }
    });*/

    vm.save = function() {

      if(vm.operations.indexOf(vm.operation) >= 0){
        return;
      }
      if (vm.operation.name 
      && vm.operation.description 
      && vm.operation.quantity) {
        vm.operations.push(vm.operation);
        vm.operation = {id: vm.operations.length + 1};
      }
    };

勾选complete version here