我想要一个与对象列表一起使用的指令,但我还需要接受双向绑定或函数绑定。
app.directive('myDir', function() {
return {
scope: {
list: "=?",
list_func: "&?listFunc"
},
controller: ['$scope', function($scope) {
$scope.get_list = function() {
if($scope.list !== undefined)
return $scope.list();
if($scope.list_func !== undefined)
return $scope.list_func()();
};
}]
};
});
但是,当我使用带有返回列表的函数的listFunc
属性时,我收到此错误:
VM607 angular.js:68 Uncaught Error:[$ rootScope:infdig] 10 $ digest()迭代次数达到。中止! 观察者在最后5次迭代中被解雇:[[{“msg”:“fn:regularInterceptedExpression”,“newVal”:19,“oldVal”:17},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“ Harry“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:”65“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:”Sally“},{”msg“:” fn:regularInterceptedExpression“,”newVal“:”66“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:9,”oldVal“:8},{”msg“:”fn:regularInterceptedExpression“,” newVal“:”val“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:”1“}],[{”msg“:”fn:regularInterceptedExpression“,”newVal“:21,”oldVal“ :19},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“Harry”},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“65”},{“msg”:“ fn:regularInterceptedExpression“,”newVal“:”Sally“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:”66“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:10 ,“oldVal”:9},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“val”},{“msg”:“fn:regularInterceptedExpression”,“newVal” :“1”}],[{“msg”:“fn:regularInterceptedExpression”,“newVal”:23,“oldVal”:21},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“Harry” },{“msg”:“fn:regularInterceptedExpression”,“newVal”:“65”},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“Sally”},{“msg”:“fn: regularInterceptedExpression“,”newVal“:”66“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:11,”oldVal“:10},{”msg“:”fn:regularInterceptedExpression“,”newVal“ :“val”},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“1”}],[{“msg”:“fn:regularInterceptedExpression”,“newVal”:25,“oldVal”:23 },{“msg”:“fn:regularInterceptedExpression”,“newVal”:“Harry”},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“65”},{“msg”:“fn: regularInterceptedExpression“,”newVal“:”Sally“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:”66“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:12,” oldVal“:11},{”msg“:”fn:regularInterceptedExpression“,”newVal“:”val“},{”msg“:”fn:regularInterceptedExpression“,”newVal“:”1“}],[{” msg“:”fn:regularInter ceptedExpression“,”newVal“:27,”oldVal“:25},{”msg“:”fn:regularInterceptedExpression“,”newVal“:”Harry“},{”msg“:”fn:regularInterceptedExpression“,”newVal“ :“65”},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“Sally”},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“66”},{“msg” :“fn:regularInterceptedExpression”,“newVal”:13,“oldVal”:12},{“msg”:“fn:regularInterceptedExpression”,“newVal”:“val”},{“msg”:“fn:regularInterceptedExpression” “的newval”: “1”}]] http://errors.angularjs.org/1.6.2/$rootScope/infdig?p0=10&p1=%5B%5B%7B%22ms…2fn%3A%20regularInterceptedExpression%22%2C%22newVal%22%3A%221%22%7D%5D%5D 在VM607 angular.js:68 在Scope。$ digest(VM607 angular.js:17893) 在Scope。$ apply(VM607 angular.js:18125) 完成后(VM607 angular.js:12233) at completeRequest(VM607 angular.js:12459) 在XMLHttpRequest.requestLoaded(VM607 angular.js:12387)
我创建了this plunker示例(打开一个javascript控制台,你可以看到这些错误),展示我需要的东西。在这个例子中,我得到了这些错误,但视图仍然得到更新。在我正在开发的应用程序(更大)上,我收到了很多$digest
错误,导致网站速度变慢,视图也无法更新。
在无限循环中结束函数的最佳方法是什么?
答案 0 :(得分:2)
Angular在get_list()
表达式上注册隐式$watchCollection。此表达式将被调用至少两次,因为angular想要检查模型是否已稳定。
<ul>
<li ng-repeat="obj in get_list()">
name: {{ obj.name }}<br />
age: {{ obj.age }}
</li>
</ul>
每次调用get_list()
时,您的代码都会返回不同的对象数组,因此angular会继续消化,直到达到最大摘要周期限制。
$scope.get_list = function(val) {
return function() {
return [ { name: "val", age: val } ];
}
}
即使内容相同,该函数每次调用时都会创建新对象。
避免在模板中使用函数调用。而是将值放在范围上,让指令对这些值的变化做出反应。
来自文档:
错误:$ rootScope:infdig
当应用程序的模型变得不稳定并且每个
$digest
周期触发状态更改和后续$digest
周期时,会发生此错误。 AngularJS检测到这种情况并防止无限循环导致浏览器无响应。一个常见错误是绑定到每次调用时生成新数组的函数。例如:
<div ng-repeat="user in getUsers()">{{ user.name }}</div>
$scope.getUsers = function() { return [ { name: 'Hank' }, { name: 'Francisco' } ]; };
由于
getUsers()
返回一个新数组,AngularJS确定每个$digest
周期的模型不同,从而导致错误。如果元素没有改变,解决方案是返回相同的数组对象:var users = [ { name: 'Hank' }, { name: 'Francisco' } ]; $scope.getUsers = function() { return users; };
我应该放弃这种功能并使用过滤器吗?
TL; DR是的。
组件应该充当“皮肤”。它们应该只显示给它们的数据并将用户事件传递给父控制器。模型应该是Single Source of Truth。指令不需要从父控制器获取数据。
表达式&
绑定应该仅用于将用户事件传递给父控制器。然后,父控制器应该适当地更改模型。这个Separation of Concerns使得应用程序更易于理解,调试,测试和维护。
还有一个问题:这也适用于返回函数的函数,对吗?
应避免使用“函数返回函数”模式。这使得一个令人困惑的模板。而是使用locals调用函数:
<my-component on-event="gotEvent($event)">
</my-compnent>
scope: { onEvent: "&" },
template: `<input ng-model=myModel ng-change="myChange()" />`,
link: function(scope, elem, attrs) {
scope.myChange = function() {
scope.onEvent({$event: myModel});
};
}
我建议在$
前加上局部变量,以区别于父范围变量。有些人建议使用$event
来符合Angular 2 +的惯例。
来自文档:
&
或&attr
- 提供了在父作用域的上下文中执行表达式的方法。如果未指定attr名称,则假定属性名称与本地名称相同。给定<my-component my-attr="count = count + $value">
和隔离范围定义scope: { localFn:'&myAttr' }
,隔离范围属性localFn
将指向count = count + $value
表达式的函数包装器。通常需要通过表达式将数据从隔离范围传递到父范围。这可以通过将局部变量名称和值的映射传递到表达式包装器fn来完成。例如,如果表达式为increment($amount)
,那么我们可以通过将localFn
称为localFn({$amount: 22})
来指定金额值。