使用Angular指令导致错误:达到10次$digest()迭代。中止。

3

http://plnkr.co/edit/dBe36L6vwOZOykujFRfg

在 Plunker 中,我遇到了以下 AngularJS 错误: "10 $digest() iterations reached. Aborting!"

当在 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:{\"name\":\"apple\"}; oldVal:{\"name\":\"apple\"}"], ["fn: parentValueWatch; newVal:{\"name\":\"apple\"}; oldVal:{\"name\":\"apple\"}"], ["fn: parentValueWatch; newVal:{\"name\":\"apple\"}; oldVal:{\"name\":\"apple\"}"], ["fn: parentValueWatch; newVal:{\"name\":\"apple\"}; oldVal:{\"name\":\"apple\"}"], ["fn: parentValueWatch; newVal:{\"name\":\"apple\"}; oldVal:{\"name\":\"apple\"}"]] at 错误(native) at Object.$digest (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:7925:19)       at Object.$apply (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:8097:24)       at done (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:9111:20)       at completeRequest(https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:9274:7)       at 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];
  };
});
2个回答

2
问题在于传递数据给Angular的方式。Angular具有出色的数据绑定功能,它会检查模型是否发生更改并更新UI。一旦UI更新,它会再次检查下一轮更改。如果数据不断发生变化,可能会陷入循环中。 在这种特殊情况下,Angular无法理解数据是相同的。每个$digest循环都会接收到新数组,并假设数据已更改,更新UI并开始再次检查。
确保您不会在每个$digest循环中从UI更新数组或返回新数组。 例如, 这将调用无限循环:
$scope.aFruit= function() {
  return [
  {"name":"apple"},
  {"name":"orange"},
  {"name":"banana"},
];
};

这将正常工作,因为对数组的引用保持不变。
var myFruits =   return [
      {"name":"apple"},
      {"name":"orange"},
      {"name":"banana"},
    ]    
$scope.aFruit= function() {
    myFruits;
    };

JanisP是正确的,这是我假设你想要它执行的操作:http://plnkr.co/edit/cFchj9uxVZRj5Fe8L5Al?p=preview - hsiung
我建议您查看Angular 1.5中的新组件方法,它们是更简洁的指令。http://plnkr.co/edit/7leRr2TfoVOSfdVjxNK0?p=preview - hsiung
@JanisP 更新2,我已经摆脱了所有的$scope引用,但仍然看到相同的问题。如果我需要一个属性是动态的(计算出来的)并且还要传递到指令中,似乎会抛出这个错误。 - Buchannon
请查看我发布的答案是否达到了您想要的目标。 - hsiung
哇,我不是要贬低你...只是说也许OP想在控制器中保留逻辑。而且我不明白传入字符串有什么问题,因为这是他在模板中使用的。显然,如果对象上有更多属性并且需要整个对象,则会采用不同的方法。 - hsiung
显示剩余5条评论

-1

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

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()}} />

希望这可以帮到你,还有另一种方法,但如果你想在模板中调用你的方法这就是你必须这样做的方式。


不错的尝试,但我想将整个对象传递给模板,而不仅仅是其中一个属性。我知道模板目前只使用了“name”属性,但这只是我在另一个项目中尝试做的事情的一个非常简化的示例。 - Buchannon
好的,如果您想传递整个对象,则无法复制它。这就是Janis最初说的。您正在每个digest周期上生成一个新对象,因此angular不知道何时停止。
  • 您可以使用'&'绑定将函数传递到指令中并在其中调用该函数
  • 在控制器中调用函数并将输出分配给作用域变量,然后将该新对象传递给指令
  • 您可以像Janis一样将逻辑放在指令中
  • 或者您可以对原始集合进行操作(即不要复制它)
- hsiung

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接