为什么这个Angular ui路由器代码在$ digest中导致无限循环?

时间:2014-02-07 15:41:48

标签: angularjs angular-ui-router

我尽可能地将代码煮熟了。关于嵌套状态和事件处理/广播的事情导致无限循环。在Chrome中我可以暂停它并看到它在Angular的$digest函数中永远循环。知道为什么吗?这是我的示例代码中的错误,还是AngularUI Router中的错误?

<!doctype html>
<html ng-app='bugapp' ng-controller='BugAppCtrl'>
<head>
  <script src='//code.jquery.com/jquery-1.10.1.min.js'></script>

  <!-- Angular 1.2.11 -->
  <script src='//ajax.googleapis.com/ajax/libs/angularjs/1.2.11/angular.js'></script>

  <!-- UI router 0.2.8 -->
  <script src='//cdn.jsdelivr.net/angular.ui-router/0.2.8/angular-ui-router.js'></script>

  <script>
angular.module('bugapp', ['ui.router'])
  .run(function ($rootScope, $state, $stateParams) {
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;
  })
  .config(function ($locationProvider, $stateProvider, $urlRouterProvider) {
    $locationProvider.html5Mode(false);

    $stateProvider
      .state("root", {
        abstract: true,
        url: "/servletContext?asUser",
        template: '<div ui-view></div>'  // ???
      })
      .state("root.home", {
        abstract: true,
        url: "/home",
        template: "<div ng-if='hasData()' ui-view ></div>"

      })
      .state("root.home.profile", {
        url: "/profile",
        template: '<div>whatever</div>'
      })

  })
  .controller('BugAppCtrl', function ($scope, $state, $stateParams, $log, $location) {
    $log.log('BugAppCtrl: constructor');

    $scope.hasData = function() {
      var res = !!$scope.foo;
      // $log.log("hasData called, returing " + res + " foo is " + $scope.foo);
      return res;
    };

    $scope.$on('$stateChangeSuccess', function () {
      $log.log("State changed! (to " + $state.current.name + ")");
      $scope.foo = 'junk';
      $scope.$broadcast("resetfoo");
    });

    $state.go('root.home.profile');
  });
  </script>
</head>
<body>
  <div ui-view></div>
</body>
</html>

1 个答案:

答案 0 :(得分:5)

我怀疑这是UI路由器中的一个错误,原因有两个:

  1. 我尝试了您的代码,然后尝试降级UI的版本 路由器到0.2.7。当我使用0.2.7时,它有效。
  2. 即使您继续使用UI路由器的0.2.8版本,如果您通过$ location而不是$ state执行状态更改,它也能正常工作。以下是使用$ location而不是$ state.go调用的示例:

    $location.path('/servletContext/home/profile');
    
  3. 虽然我使用并推荐UI路由器(不能没有嵌套视图),但如果您在将来发现当用户尝试转到某些页面时您想要进行任何类型的拦截或重定向,我建议使用$ location.path而不是$ state,原因我描述了in a blog post

    编辑:我之前没有尝试使用参数,只是尝试使用您发布的代码(我创建了第二个控制器并将其分配到'root.home.profile'状态),并且有用。 UI路由器的说明为here。但基本上,如果您在状态定义中设置URL的方式与使用UI路由器的方式相同:

    url: "/profile/:foo",
    

    然后在$ location.path调用中添加路径中的参数:

    $location.path('/servletContext/home/profile/12');
    

    您可以从

    访问控制器中的12
    $stateParams.foo