Javascript $watch'ing Angular 指令中的数据变化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13980896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
$watch'ing for data changes in an Angular directive
提问by Evil Closet Monkey
How can I trigger a $watchvariable in an Angular directive when manipulating the data inside (e.g., inserting or removing data), but not assign a new object to that variable?
如何$watch在操作内部数据(例如,插入或删除数据)时触发Angular 指令中的变量,但不为该变量分配新对象?
I have a simple dataset currently being loaded from a JSON file. My Angular controller does this, as well as define a few functions:
我有一个当前正在从 JSON 文件加载的简单数据集。我的 Angular 控制器执行此操作,并定义了一些函数:
App.controller('AppCtrl', function AppCtrl($scope, JsonService) {
// load the initial data model
if (!$scope.data) {
JsonService.getData(function(data) {
$scope.data = data;
$scope.records = data.children.length;
});
} else {
console.log("I have data already... " + $scope.data);
}
// adds a resource to the 'data' object
$scope.add = function() {
$scope.data.children.push({ "name": "!Insert This!" });
};
// removes the resource from the 'data' object
$scope.remove = function(resource) {
console.log("I'm going to remove this!");
console.log(resource);
};
$scope.highlight = function() {
};
});
I have a <button>that properly called the $scope.addfunction, and the new object is properly inserted into the $scope.dataset. A table I have set up does update each time I hit the "add" button.
我有一个<button>正确调用该$scope.add函数的函数,并且新对象已正确插入到$scope.data集合中。每次我点击“添加”按钮时,我设置的表格都会更新。
<table class="table table-striped table-condensed">
<tbody>
<tr ng-repeat="child in data.children | filter:search | orderBy:'name'">
<td><input type="checkbox"></td>
<td>{{child.name}}</td>
<td><button class="btn btn-small" ng-click="remove(child)" ng-mouseover="highlight()"><i class="icon-remove-sign"></i> remove</button></td>
</tr>
</tbody>
</table>
However, a directive I set set up to watch $scope.datais not being fired when all this happens.
但是,$scope.data当所有这些发生时,我设置为监视的指令不会被触发。
I define my tag in HTML:
我在 HTML 中定义我的标签:
<d3-visualization val="data"></d3-visualization>
Which is associated with the following directive (trimmed for question sanity):
与以下指令相关联(为了问题的完整性而进行了调整):
App.directive('d3Visualization', function() {
return {
restrict: 'E',
scope: {
val: '='
},
link: function(scope, element, attrs) {
scope.$watch('val', function(newValue, oldValue) {
if (newValue)
console.log("I see a data change!");
});
}
}
});
I get the "I see a data change!"message at the very beginning, but never after as I hit the "add" button.
我"I see a data change!"一开始就收到消息,但在我点击“添加”按钮之后就再也没有收到消息。
How can I trigger the $watchevent when I'm just adding/removing objects from the dataobject, not getting a whole new dataset to assign to the dataobject?
$watch当我只是从data对象中添加/删除对象,而不是获取一个全新的数据集来分配给对象时,如何触发事件data?
回答by Liviu T.
You need to enable deep object dirty checking. By default angular only checks the reference of the top level variable that you watch.
您需要启用深度对象脏检查。默认情况下,angular 仅检查您观察的顶级变量的引用。
App.directive('d3Visualization', function() {
return {
restrict: 'E',
scope: {
val: '='
},
link: function(scope, element, attrs) {
scope.$watch('val', function(newValue, oldValue) {
if (newValue)
console.log("I see a data change!");
}, true);
}
}
});
see Scope. The third parameter of the $watch function enables deep dirty checking if it's set to true.
见范围。如果 $watch 函数的第三个参数设置为 true,则启用深度脏检查。
Take note that deep dirty checking is expensive. So if you just need to watch the children array instead of the whole datavariable the watch the variable directly.
请注意,深度脏检查是昂贵的。因此,如果您只需要查看子数组而不是整个data变量,请直接查看变量。
scope.$watch('val.children', function(newValue, oldValue) {}, true);
version 1.2.x introduced $watchCollection
1.2.x 版引入了$watchCollection
Shallow watches the properties of an object and fires whenever any of the properties change (for arrays, this implies watching the array items; for object maps, this implies watching the properties)
Shallow 监视对象的属性并在任何属性更改时触发(对于数组,这意味着监视数组项;对于对象映射,这意味着监视属性)
scope.$watchCollection('val.children', function(newValue, oldValue) {});
回答by Hazarapet Tunanyan
Because if you want to trigger your data with deep of it,you have to pass 3th argument trueof your listener.By default it's falseand it meens that you function will trigger,only when your variable will change not it's field.
因为如果你想用深度触发你的数据,你必须传递true你的监听器的第三个参数。默认情况下false,它意味着你的函数会触发,只有当你的变量不会改变它的字段时才会触发。
回答by rob2universe
My version for a directive that uses jqplot to plot the data once it becomes available:
我的指令版本使用 jqplot 在数据可用后绘制数据:
app.directive('lineChart', function() {
$.jqplot.config.enablePlugins = true;
return function(scope, element, attrs) {
scope.$watch(attrs.lineChart, function(newValue, oldValue) {
if (newValue) {
// alert(scope.$eval(attrs.lineChart));
var plot = $.jqplot(element[0].id, scope.$eval(attrs.lineChart), scope.$eval(attrs.options));
}
});
}
});

