Javascript 如何基于值相等和引用相等进行观看?
AngularJS中的函数接受可选的第三个参数 如果为Javascript 如何基于值相等和引用相等进行观看?,javascript,angularjs,watch,Javascript,Angularjs,Watch,AngularJS中的函数接受可选的第三个参数 如果为false(默认值),则每当监视的参考发生变化时,手表将触发。如果为true,则每当监视对象根据更改时,监视将触发(这基本上意味着存储在监视对象中的值必须已更改) 现在,我正在寻找一种方法,如果被监视的引用或其内容发生了变化,让手表启动其功能。有没有办法做到这一点 举一个我所看到的困难的例子: 假设我有一组内容可编辑的对象: var allItems = [{id: 1, a: []}, {id: 2, a: [2, 3, 5]}, {id
false
(默认值),则每当监视的参考发生变化时,手表将触发。如果为true
,则每当监视对象根据更改时,监视将触发(这基本上意味着存储在监视对象中的值必须已更改)
现在,我正在寻找一种方法,如果被监视的引用或其内容发生了变化,让手表启动其功能。有没有办法做到这一点
举一个我所看到的困难的例子: 假设我有一组内容可编辑的对象:
var allItems = [{id: 1, a: []}, {id: 2, a: [2, 3, 5]}, {id: 3, a: [4, 6]}, {id: 4, a: []}];
“我的编辑器”作用域上的字段接收对A
属性值的引用。例如,如果选择了项目1,则会出现以下情况:
$scope.currentItem = [];
此外,我在该字段上注册了一块手表,用于检查值是否相等:
$scope.$watch('currentItem', watchFunc, true);
现在,我必须区分两种情况:
- 用户使用编辑器UI将所选项目中的
扩展为[]
[4,6]
- 用户选择项目3
watchFunc
中,乍一看,这两个更改似乎是相同的。为了区分是否选择了新项目,我需要以某种方式保留以前的ID,如果它与当前ID不同,我需要忽略更改(因为数据中没有编辑任何内容,只切换了选定的项目)。然后,我需要使用watchFunc
将当前项目ID设置为下一次调用的上一个ID
但是,在以下情况下,这是有问题的:
角度.equals
触发手表。因此,当选择更改时,所选项目ID将不会更新。相反,在步骤3中会注意到不同的项目ID,这会导致忽略实际的编辑操作
显然,这个例子非常简单;实际上,我的对象图由对象的嵌套数组组成,每个数组都有不同的相关属性。工作JSFIDLE: 希望这就是你想要的 测试场景:
1. Select 1
2. Input 4 => Add
3. Input 6 => Add
4. Select 3
5. $watch occurs
AngularJS:
var myApp = angular.module('myApp',[]);
myApp.controller('myCtrl', myCtrl);
function myCtrl($scope) {
$scope.allItems = [{id: 1, a: []}, {id: 2, a: [2, 3, 5]}, {id: 3, a: [4, 6]}, {id: 4, a: []}];
$scope.currentItemObject = {};
$scope.currentItem = [];
$scope.updateCurrentItem = function(item){
$scope.currentItem = angular.copy(item.a);
};
$scope.addItem = function(){
if($scope.newItem !== undefined){
$scope.currentItem.push($scope.newItem);
$scope.newItem = undefined;
}
};
$scope.$watch(function(){
return {id: $scope.currentItemObject.id, a: $scope.currentItem};
},function(newValue, oldValue){
if(newValue !== oldValue){
console.log('$watch', $scope.currentItem);
$scope.lastUpdate = new Date().toLocaleTimeString();
}
},true);
}
<div ng-controller="myCtrl">
<label>Items:
<select ng-options="item as item.id for item in allItems"
ng-model="currentItemObject"
ng-change="updateCurrentItem(currentItemObject)">
<option style="display:none" value="">-- select item --</option>
</select>
</label>
<div>
<label>New item
<input type="number" ng-model="newItem">
</label>
<button type="button" ng-click="addItem()">
Add
</button>
</div>
<div>
Current item: {{currentItem}}
</div>
<br/>
<pre>
Last update: {{lastUpdate}}
</pre>
</div>
HTML:
var myApp = angular.module('myApp',[]);
myApp.controller('myCtrl', myCtrl);
function myCtrl($scope) {
$scope.allItems = [{id: 1, a: []}, {id: 2, a: [2, 3, 5]}, {id: 3, a: [4, 6]}, {id: 4, a: []}];
$scope.currentItemObject = {};
$scope.currentItem = [];
$scope.updateCurrentItem = function(item){
$scope.currentItem = angular.copy(item.a);
};
$scope.addItem = function(){
if($scope.newItem !== undefined){
$scope.currentItem.push($scope.newItem);
$scope.newItem = undefined;
}
};
$scope.$watch(function(){
return {id: $scope.currentItemObject.id, a: $scope.currentItem};
},function(newValue, oldValue){
if(newValue !== oldValue){
console.log('$watch', $scope.currentItem);
$scope.lastUpdate = new Date().toLocaleTimeString();
}
},true);
}
<div ng-controller="myCtrl">
<label>Items:
<select ng-options="item as item.id for item in allItems"
ng-model="currentItemObject"
ng-change="updateCurrentItem(currentItemObject)">
<option style="display:none" value="">-- select item --</option>
</select>
</label>
<div>
<label>New item
<input type="number" ng-model="newItem">
</label>
<button type="button" ng-click="addItem()">
Add
</button>
</div>
<div>
Current item: {{currentItem}}
</div>
<br/>
<pre>
Last update: {{lastUpdate}}
</pre>
</div>
项目:
--选择项--
新项目
添加
当前项:{{currentItem}}
上次更新:{{lastUpdate}}
注册2个带和不带第3个参数的侦听器?:)除了自定义方法之外,我想不出任何更简单的解决方案。从来没有必要这样做,但是。。这是一个非常有趣的问题。@StanislavKvitash:问题是,如果引用发生了更改,我需要抑制对值更改的反应。如果我只注册两名听众,我想我不能依赖他们的发言顺序。此外,引用更改之后可能会或可能不会有值更改,这取决于两个引用对象是否恰好具有相同的内容。@charlietfl:这可能是一个糟糕的设计。然而,总的来说,意识到某个元素以某种方式发生了变化,这听起来是合理的,对吗?不管某个值或整个引用是否已更改。。喜欢好。与angular 2一样?值在部分更改时应更改其引用,这样就无需执行深入比较。