Angular.js仅监视特定的对象属性

时间:2013-03-20 11:17:13

标签: javascript object angularjs watch angularjs-scope

基本上我想要这个http://plnkr.co/edit/3yfXbo1c0llO40HZ8WNP?p=preview但是当我改变某些东西时,手表不会触发..

我知道这会有用

$scope.$watch('stuff', function (newVal, oldVal) {
    console.log(oldVal, newVal);

}, true);

但是因为我想在手表里面做一些总结而且我不想不必要地循环或重新组合那些没有改变的值。

//编辑 - 请注意,plnkr示例只是从实际应用程序中提取,您可以在其中添加和删除行等等,例如从ng-repeat外部的另一个输入修改总数(某些事物和某些事物的总和)。

4 个答案:

答案 0 :(得分:6)

我不会做手表,因为你的阵列有多大,可能会非常费力。相反,我只想创建一个过滤器:

HTML:

Sum of something is: {{ stuff | sum:'something' }}<br/>
Sum of somethingelse is: {{ stuff | sum:'somethingelse' }}

使用Javascript:

.filter("sum", function(){
    return function(input, params){
        var totalSum = 0;
        for(var x = 0; x < input.length; x++){
            totalSum += input[x][params];
        }
        return totalSum;
    }
})

plnkr:http://plnkr.co/edit/p6kM3ampSuMXnwqcteYd?p=preview

答案 1 :(得分:4)

在我为你的问题找到解决方案后,我到处都是微笑。这个解决方案不仅要观察单个对象,而且还不会完成整个对象的完整循环以进行求和。

http://plnkr.co/edit/oPWobcLLtJlxs5vjTYyc?p=preview

app.controller('MainCtrl', function($scope) {
  $scope.stuff = STUFF;
  var i;
  $scope.sumOfSomething = 0;
  $scope.sumOfSomethingElse = 0;

  for(i=0;i < $scope.stuff.length;i++ ){
    $scope.$watch('stuff['+i+'].something', function (newVal,oldVal) {
      // happens when the watch is registered.
      if(oldVal === newVal){
        $scope.sumOfSomething += +newVal;
        return;
      }
      if(newVal){
        $scope.sumOfSomething += + (newVal - oldVal);
      }
    });

    $scope.$watch('stuff['+i+'].somethingelse', function (newVal,oldVal) {
      // happens when the watch is registered. 
      if(oldVal === newVal){
        $scope.sumOfSomethingElse += +newVal;
        return;
      }

      if(newVal){
        $scope.sumOfSomethingElse += + (newVal - oldVal);
      }

    });  
  }
});

顺便说一下,如果STUFF中有大量对象,我不知道这个解决方案会有多优化。此外,如果STUFF中的对象数量发生变化,这将不会起作用。我们基本上做的是使用角度的脏检查循环来为我们做总结。

还要注意监听器中newVal和oldVal的顺序。你的订单错了。

答案 2 :(得分:3)

由于$watch()采用角度表达式,因此您可以使用自定义观察器功能。在你的情况下,观察变化的最简单方法就是将你感兴趣的所有字段相加然后返回一个对于角度来说很好且有效的数字,你的总和就可以渲染了。

var sumThings = function(obj, field) {
  var val = 0;
  obj.forEach(function(o) {
    val += parseInt(o[field]);
  });
  return val;
};

$scope.$watch(function() { return sumThings($scope.stuff, "something")}, function (newVal, oldVal) {    //console.log("watchExpression('something') fired!", oldVal, newVal);
  $scope.somethingSum = newVal;
});

$scope.$watch(function() { return sumThings($scope.stuff, "somethingelse")}, function (newVal, oldVal) {
  $scope.somethingelseSum = newVal;
});

基本上,通过做总结,你正在进行自己的脏检查。如果您的对象比您在此处显示的更复杂,它将比$watch(STUFF, true)更有效。

您更新的plnkr:http://plnkr.co/edit/d7CvERu3XGkub4l6f1yw?p=preview

答案 3 :(得分:1)

好吧,如果我得到它,你只想在somethingsomethingelse内部对象相加时将它们加起来。如果更改位于其中一个内部对象中,则不希望遍历所有其他内部对象。

好吧,由于没有$watch,您的stuff.property没有被解雇,并且没有像stuff.*.something这样的模式。

如果您知道从阵列推送或拉出对象的时刻,那么您可以在将每个对象插入阵列之前/之后单独应用$scope.$watch(object, function(){}, true)。如果您不知道这一刻,那么您将需要$watch整个阵列,并且当发生更改时,请逐个运行所有注销功能并再次$watch这些功能。

无论如何,现在浏览器中的循环非常快,除了你正在进行大量计算并且你有数百万个对象(本来会出现内存问题)你可能会对它很好。因此,只有在计算量非常大的情况下,才能单独$watch将它们全部分开,这可能构成系统性能。