【问题标题】:Angular ui-router struggleAngular ui路由器之争
【发布时间】:2015-08-20 14:44:43
【问题描述】:

嗯,我有这个项目,而 ui-router 给我带来了困难。我做了一个快速的 Plunker 演示:http://plnkr.co/edit/imEErAtOdEfaMMjMXQfD?p=preview

所以基本上我有一个主视图index.html,其他顶级视图被注入其中,例如operations.index.html。当顶层视图中有多个命名视图时,我的大脑开始痛苦,operations.detail.htmloperations.list.html 被注入到 operations.index.html 中,而 operations.index.html 又被注入到 index.html 中。

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

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

现在,检查一下奇怪的行为:转到Operations,然后再次单击Operations 导航栏项。一切都消失了。如果我这样做 Operations -> 选择 Operation 1 -> 选择 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 来实现我的目的。干杯。

【问题讨论】:

    标签: angularjs angular-ui-router state


    【解决方案1】:

    the updated plunker

    我刚刚使用了这个问答中的技术:Redirect a state to default substate with UI-Router in AngularJS

    我添加了 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

    【讨论】:

    • 你是救生员。我真的用尽了我的智力来找出所需的状态设置配置,例如abstract 等等。救了我的是1)添加redirectTo设置和redirector; 2) 将controller 设置添加到状态,因为现在$stateParams.id 在每次路线更改(即选择操作)时都会更新。现在没有什么能阻止我们征服世界 呵呵呵呵 :D 干杯,伙计!
    • 如果这有效,我真的很高兴。先生,享受强大的 UI-Router ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    • 2016-01-06
    • 1970-01-01
    相关资源
    最近更新 更多