AngularJS:观察对象数组中的特定属性,以获取属性值的更改

时间:2014-10-24 17:27:41

标签: angularjs angularjs-directive watch

在我的自定义指令中,我根据数据源数组中的对象数量向DOM添加元素。我需要在每个对象中观察特定属性。当我将这些元素添加到DOM时,我想在checked数组中的每个对象的toppings属性上设置$ watch,但它不起作用,我不知道为什么。我在函数内部设置了一个断点,当属性从true变为false或false变为true时应调用该断点,但永远不会调用该函数。原因很明显吗?我只是在学习Angular,所以我很容易犯一个愚蠢的错误。

$scope.bits = 66;  (i.e. onions and olives)


$scope.toppings = [
    { topping: 1, bits: 2, name: 'onions' },
    { topping: 2, bits: 4, name: 'mushrooms' },
    { topping: 3, bits: 8, name: 'peppers' },
    { topping: 4, bits: 16, name: 'anchovies' },
    { topping: 5, bits: 32, name: 'artichokes' },
    { topping: 6, bits: 64, name: 'olives' },
    { topping: 7, bits: 128, name: 'sausage' },
    { topping: 8, bits: 256, name: 'pepperoni' }
     ]

模型中的每个对象都会获得一个新的checked属性,该属性将为true或false。

注意:对象数组最多包含十几个项目。表现不是问题。

link: function link(scope, iElement, iAttrs, controller, transcludeFn) {


  <snip>

 // At this point  scope.model refers to $scope.toppings. Confirmed.

  angular.forEach(scope.model, function (value, key) {

     // bitwise: set checked to true|false based on scope.bits and topping.bits

     scope.model[key].checked = ((value.bits & scope.bits) > 0);  


     scope.$watch(scope.model[key].checked, function () {
         var totlBits = 0;
         for (var i = 0; i < scope.model.length; i++) {
            if (scope.model[i].checked) totlBits += scope.model[i].bits;
         }
          scope.bits = totlBits;
      });

   });

     <snip>

4 个答案:

答案 0 :(得分:2)

对象数组:

$scope.toppings = [
   { topping: 1, bits: 2, name: 'onions' },
   { topping: 2, bits: 4, name: 'mushrooms' },
   { topping: 3, bits: 8, name: 'peppers', checked:undefined /*may be*/ }
];

观看使用AngularJs $ WatchCollection:

我们将创建一个我们正在观察集合的元素属性数组(objects),而不是监视上面的.checked数组,这可以改变对象中的任何属性。 / p>

我们filter数组的元素仅监视那些.checked定义的元素和map元素到角watchCollection的数组。

当更改触发时,我将使用lodash difference方法比较旧的和新的(.checked)数组,以获得确切的更改元素。

 $scope.$watchCollection(
                //Watch Function
                ()=>($scope.toppings.filter(tp=>tp.checked!=undefined).map(tp=>tp.checked)),

                //Listner
                (nv,ov)=>{
                if(nv==ov||nv=="undefined")return;

                //Use lodash library to get the changed obj
                let changedTop= _.difference(nv,ov)[0];

                //Here you go..
                console.log("changed Topping",changedTop);
            })

答案 1 :(得分:1)

$ scope。$ watch的watchExpression参数应该是字符串或函数。我没有对此进行过广泛的实验(尽可能避免使用明确的手表),但我认为当你观看简单的手表时它也会起作用。范围属性作为对象引用,但对于更复杂的引用则不太好。

我认为如果您将引用作为字符串提供,例如&#39;模型[&#39; +键+&#39;]。已选中&#39;那么你可能会取得一些成功(我只是这样说,因为我之前已经用$ watchCollection做了类似的事情。)

或者你应该能够提供一个功能,例如

$scope.$watch(function() { return scope.model[key].checked; }, function() { ... });

希望这有帮助!

答案 2 :(得分:1)

使用MAP收集所需的所有属性值+将它们转换为小字符串表示形式(在本例中为1和0),然后将它们连接成一个可以观察到的字符串。

打字稿示例:

        $scope.$watch(
            () => this.someArray.map(x => x.selected ? "1" : "0").join(""),
            (newValue, oldValue, scope) => this.onSelectionChanged(this.getSelectedItems()));

答案 3 :(得分:0)

改为使用$watchCollection

来自docs:

$ watchCollection(obj,listener); Shallow监视对象的属性,并在任何属性发生更改时触发(对于数组,这意味着要观察数组项;对于对象映射,这意味着要观察属性)。如果检测到更改,则会触发侦听器回调。

通过标准的$ watch操作观察obj集合,并在每次调用$ digest()时检查obj集合,以查看是否已添加,删除或移动任何项目。 只要obj中的任何内容发生变化,就会调用监听器。示例包括添加,删除和移动属于对象或数组的项目。