【问题标题】:Using angular directive causes error: 10 $digest() iterations reached. Aborting使用 angular 指令会导致错误:达到 10 次 $digest() 迭代。中止
【发布时间】:2016-11-15 08:11:25
【问题描述】:

http://plnkr.co/edit/dBe36L6vwOZOykujFRfg

在 plunker 中,我收到以下角度错误:“已达到 10 个 $digest() 迭代。正在中止!”

该逻辑在 index.html 中使用时有效:

<h1>(working) Fruit from main document: {{vm.randomFruit().name}}</h1>

但是当我尝试使用传入的对象调用指令中的类似代码时抛出错误:

<h1>(causing error) Fruit from directive template: {{fruit.name}}</h1>

如果我只是在范围函数中执行此操作,它似乎也不会在指令中引发错误:

//this works for both instances
return vm.fruits[0];

但是,当我以任何方式触摸 $scope.fruits 时,即使只是复制它,它也会在指令版本上出现错误。

//something about touching the array here exposes the error, even though it still works
var x = [];
angular.copy(vm.fruits, x);
return x[0];

为什么这里会抛出这个错误?似乎是某种循环依赖,但为什么只在指令版本上呢?

有没有更好的方法来使用更标准的指令、模板和传入的参数对象?

错误:达到 10 次 $digest() 迭代。中止!观察者开枪 最后 5 次迭代: [["fn: parentValueWatch; newVal: {\"名称\":\"苹果\"}; oldVal: {\"name\":\"apple\"}"],["fn: 父值观察; newVal: {\"名称\":\"苹果\"};旧值: {\"name\":\"apple\"}"],["fn: parentValueWatch;新值: {\"名称\":\"苹果\"}; oldVal: {\"name\":\"apple\"}"],["fn: 父值观察; newVal: {\"名称\":\"苹果\"};旧值: {\"name\":\"apple\"}"],["fn: parentValueWatch;新值: {\"名称\":\"苹果\"}; oldVal: {\"name\":\"apple\"}"]] 在错误(本机) 在 Object.$digest (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:7925:19) 在 Object.$apply (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:8097:24) 完成后 (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:9111:20) 在完成请求 (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:9274:7) 在 XMLHttpRequest.xhr.onreadystatechange (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:9244:11)


更新 1

将 aFruit() 更新为 randomFruit() 以便更好地展示我的问题:

$scope.randomFruit = function() {
//something about touching the array here exposes the error, even though it still works
var x = [];
angular.copy($scope.fruits, x);
//do some custom stuff here, sorting, etc. <whatever>
var randomIndex = Math.floor((Math.random() * x.length));
return x[randomIndex];
};

更新 2

被告知不要使用 $scope,因此将其从控制器中完全删除。仍然看到同样的错误。

myApp.controller('FruitCtrl', function() {
  var vm = this;
  vm.fruits = fruits;

  vm.randomFruit = function() {
    //something about touching the array here exposes the error, even though it still works
    var x = [];
    angular.copy(vm.fruits, x);
    //do some custom stuff here, sorting, etc. <whatever>
    var randomIndex = Math.floor((Math.random() * x.length));
    return x[randomIndex];
  };
});

【问题讨论】:

    标签: angularjs angularjs-directive angularjs-scope directive circular-dependency


    【解决方案1】:

    问题在于方法,如何将数据传递给 Angular。 Angular 有很棒的数据绑定,它会检查模型是否改变并更新 UI。更新 UI 后,它会再次检查下一轮更改。如果数据一直在变化,它可能会卡在循环中。

    在这种特殊情况下,Angular 不理解数据是相同的。它在每个摘要循环中接收新数组并假定数据已更改,更新 UI 并再次开始检查。

    确保您没有在每个 $digest 循环中从 UI 更新数组或在每个 $digest 循环上返回新数组。 例如 这将调用无限循环:

    $scope.aFruit= function() {
      return [
      {"name":"apple"},
      {"name":"orange"},
      {"name":"banana"},
    ];
    };
    

    这将正常工作,因为对数组的引用保持不变

    var myFruits =   return [
          {"name":"apple"},
          {"name":"orange"},
          {"name":"banana"},
        ]    
    $scope.aFruit= function() {
        myFruits;
        };
    

    【讨论】:

    • JanisP 是正确的,这就是我假设你想要它做的事情:plnkr.co/edit/cFchj9uxVZRj5Fe8L5Al?p=preview
    • 另外,我建议您查看 Angular 1.5 中的新组件方法,这是更简洁的指令。 plnkr.co/edit/7leRr2TfoVOSfdVjxNK0?p=preview
    • @hsiung - 不,简单地返回第一个元素不是我的意思。这是一个更复杂的函数,例如从数组中返回一个随机元素或对数组进行排序并从中返回顶部 值。我已经更新了原始问题,以便更好地理解我的观点。
    • @Buchannon Update 1 仍然是同一件事 - 您在每个摘要周期都重新创建并返回新数组。它导致无限循环。尽量不要在视图中使用作用域函数,它们在屏幕渲染时会执行多次(尝试在它们中抛出断点以查看它们是如何工作的)
    • @JanisP 更新 2,我摆脱了所有 $scope 引用,但仍然看到同样的问题。如果我需要一个动态的(计算的)属性并传递给指令,它似乎会抛出这个错误。
    【解决方案2】:

    哦,好的,明白了! 有两种方法可以做到这一点,但我相信您正在寻找这种方法。

    http://plnkr.co/edit/E1y9nqh0DdaHGW2hi4AM?p=preview

    问题是您的方法正在返回一个对象,但您想获取字符串值。所以我们把方法改成这样:

    $scope.randomFruit = function() {
      var x = [];
      angular.copy($scope.fruits, x);
      var randomIndex = Math.floor((Math.random() * x.length));
      return x[randomIndex].name;
    };
    

    接下来,我们需要更改我们的组件绑定以接受带有“@”的字符串

    bindings: { fruit: '@' },
    

    最后,我们需要调用模板中的方法,并使用插值将其设置为我们传递给组件的值:

    <show-fruit fruit={{randomFruit()}} />
    

    希望这会有所帮助,还有另一种方法,但是如果您想在 in 模板中调用您的方法,这就是您必须这样做的方式。

    【讨论】:

    • 不错的尝试,但我想将整个对象传递给模板,而不仅仅是属性之一。我知道模板现在只使用“名称”属性,但这是一个非常简化的示例,说明我正在尝试在另一个项目中使用我的代码库。
    • 好的,所以如果您尝试传入整个对象,则无法复制它。这就是贾尼斯最初所说的。您在每个摘要周期都生成一个新对象,因此 angular 不知道何时停止。 - 您可以使用 '&' 绑定传递函数并在指令中调用函数 - 在控制器中调用函数并将输出分配给范围变量,然后将该新对象传递给指令 - 您可以执行 Janis 的操作做了并将逻辑放在指令中 - 或者您可以对原始集合进行操作(即不要复制它)
    猜你喜欢
    • 2015-05-30
    • 1970-01-01
    • 2012-11-30
    • 1970-01-01
    • 2015-05-07
    • 2016-08-05
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多