如何根据价值平等和参考平等观察?

时间:2017-12-01 12:21:56

标签: javascript angularjs watch

AngularJS中的$watch函数接受可选的第三个参数。

如果是false(默认值),只要观察的参考值发生变化,手表就会触发。如果是true,只要观察对象根据angular.equals发生变化,手表就会触发(这基本上意味着观察对象中存储的值必须更改)。

现在,如果观看的参考其内容发生了变化,我正在寻找让手表触发其功能的方法。有没有办法实现这个目标?

提供我所看到的困难的一个例子:

我们假设我有一系列内容可编辑的对象:

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。

但是,在以下情况下,这是有问题的:

  1. 选择了第1项。
  2. 用户选择第4项。
  3. 用户在第4项中添加了一些内容。
  4. 此处的问题是,第二个操作会根据angular.equals触发监视。因此,当选择更改时,不会更新所选项目ID。相反,将在步骤3中注意到不同的项ID,这将导致实际的编辑操作被忽略。

    显然,这个例子非常简单;实际上,我的对象图由嵌套的对象数组组成,每个对象具有各种相关属性。

1 个答案:

答案 0 :(得分:0)

工作jsfiddle:http://jsfiddle.net/qybc07zs/

希望这是你正在寻找的东西。

测试场景:

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);
}

<强> HTML:

<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>