如何“解开”一个expression式

说我有一个大的数组重复。

当ng-repeat运行时,它将该数组的每个元素都添加到一个独立的作用域中,并将该数组本身放在一个作用域中。 这意味着$ digest会检查整个数组是否发生更改,最重要的是,它将检查数组中每个单独的元素是否发生更改。

看到这个笨蛋是我正在谈论的一个例子。

在我的用例中,我从不改变数组中的单个元素,所以我不需要让他们看。 我只会改变整个数组,在这种情况下ng-repeat会重新呈现整个表格。 (如果我错了,请让我知道..)

在(比方说)1000行的数组中,这是1000多个expression式,我不需要评估。

如何在观看主arrays的同时从观察者注销每个元素?

也许而不是取消注册,我可以更多地控制我的$摘要,并以某种方式跳过每一行?

这个具体案例实际上是一个更普遍问题的例子。 我知道$ watch会返回一个“注销”function ,但是当指令注册手表时,这并不是什么好事,大部分时间都是这样。

要有一个大arrays,你不看每一个项目的中继器。

你将需要创build一个自定义指令,它接受一个参数,然后expression式到你的数组,然后在链接函数中,你只需要看这个数组,然后你可以用链接函数以编程方式刷新HTML(而不是使用NG-重复)

像(伪代码):

app.directive('leanRepeat', function() { return { restrict: 'E', scope: { 'data' : '=' }, link: function(scope, elem, attr) { scope.$watch('data', function(value) { elem.empty(); //assuming jquery here. angular.forEach(scope.data, function(d) { //write it however you're going to write it out here. elem.append('<div>' + d + '</div>'); }); }); } }; }); 

这似乎是在屁股疼痛。

备用hackish方法

您可以循环遍历$scope.$$watchers并检查$scope.$$watchers[0].exp.exp以查看它是否与要删除的expression式相匹配,然后使用简单splice()删除它splice()电话。 这里的PITA就是像标签之间的Blah {{whatever}} Blah这样的东西就是expression式,甚至会包含回车符。

好处是,你可能只需循环遍历你的ng-repeat的$范围,并删除一切,然后明确地添加你想要的手表…我不知道。

无论哪种方式,这似乎是一个黑客。

删除由$ scope创build的观察者。$ watch

您可以使用由$watch调用返回的函数取消注册$watch

例如,要让$watch只触发一次:

 var unregister = $scope.$watch('whatever', function(){ alert('once!'); unregister(); }); 

你可以随时调用注销函数,这只是一个例子。

结论:没有一个真正的好方法来完成你所要求的

但有一点需要考虑:是否值得担心呢? 此外,将数千个logging加载到几十个DOME元素中是否真的是一个好主意? 食物的思想。

我希望有帮助。


编辑2(删除坏主意)

$ watch返回一个在调用时解绑定$ watch的函数。 所以这就是“watchOnce”所需要的一切:

 var unwatchValue = scope.$watch('value', function(newValue, oldValue) { // Do your thing unwatchValue(); }); 

编辑:看到我张贴的其他答案。

我已经以一种可以分离的方式去执行blesh的想法。 我的ngOnce指令只是破坏ngRepeat在每个项目上创build的子作用域。 这意味着范围不能从父母的scope.$digest得到, scope.$digest和观察者从不被执行。

源代码和JSFiddle的例子

指令本身:

 angular.module('transclude', []) .directive('ngOnce', ['$timeout', function($timeout){ return { restrict: 'EA', priority: 500, transclude: true, template: '<div ng-transclude></div>', compile: function (tElement, tAttrs, transclude) { return function postLink(scope, iElement, iAttrs, controller) { $timeout(scope.$destroy.bind(scope), 0); } } }; }]); 

使用它:

  <li ng-repeat="item in contents" ng-once> {{item.title}}: {{item.text}} </li> 

注意 ng-once不会创build自己的作用域,这意味着它可能会影响同级元素。 这些都做同样的事情:

  <li ng-repeat="item in contents" ng-once> {{item.title}}: {{item.text}} </li> <li ng-repeat="item in contents"> <ng-once> {{item.title}}: {{item.text}} </ng-once> </li> <li ng-repeat="item in contents"> {{item.title}}: {{item.text}} <ng-once></ng-once> </li> 

注意 这可能是一个坏主意

您可以将bindonce指令添加到您的ng-repeat 。 你需要从https://github.com/pasvaz/bindonce下载它。;

编辑 :几个注意事项:

如果您在模板中使用{{}}插值,则需要使用<span bo-text>replace它。

如果你正在使用ng-指令,你需要用正确的指令replace它们。

此外,如果您将bindonceng-repeat放在相同的元素上,则应该尝试将bindonce移至父元素(请参阅https://github.com/Pasvaz/bindonce/issues/25#issuecomment-25457970 )或者添加track by你的ng-repeat

如果您使用的是angularjs 1.3或更高版本,则可以使用单一绑定语法

 <li ng-repeat="item in ::contents">{{item}}</li> 

这将绑定该值,并且一旦运行第一个摘要循环,将移除观察者,并且该值首次从未undefined变为defined

这是一个非常有帮助的博客 。