【问题标题】:Angular.js watch only on particular object propertyAngular.js 只关注特定的对象属性
【发布时间】:2013-03-20 11:17:12
【问题描述】:

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

我知道这会奏效

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

}, true);

但是因为我想在手表内部做一些总结,我不想不必要地循环或重新总结没有改变的值..

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

【问题讨论】:

  • 没有$scope.stuff.something 变量,所以你不能$watch。
  • @Stewie 所以我应该要么观看整个 stuff,要么在一些 onchange/onkeyup 事件中使用我的求和函数,对吗?
  • 我想要somethingsomethingelse 的总和,现在当something 发生变化时,也不需要对somethingelse 进行总和
  • 需要遍历整个对象才能得到一个属性的总和,那么同时对其他属性求和会有什么不同呢?
  • 我会说只是观看整个stuff 并远离premature optimization

标签: javascript object angularjs watch angularjs-scope


【解决方案1】:

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

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

【讨论】:

  • 这使用更少的手表,让 Angular 完成更多繁重的工作。像其他示例中那样设置大量手表的循环只会随着数组大小的增长而减慢程序的速度。
  • 如果您只显示总和,而不是在内部使用它,那么我相信这是最好的方法。我唯一不同的是,我不会使用filter。您可以简单地将绑定设置为{{stuff.something + stuff.somethingelse}}。这样一来,您就可以以最低的观看成本授予价值将始终在一个或另一个变化时发生变化。
  • 我不认为你可以使用你建议的绑定,东西是一个数组,而不是一个对象。
  • 这个解决方案实际上会观察整个对象。
  • @ganaraj 你有那个来源吗?我想了解更多。
【解决方案2】:

在为您的问题想出这个解决方案后,我满脸笑容。该解决方案不仅会观察单个对象,而且不会对其余对象进行完整循环以进行求和。

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 中的对象数量将发生变化,这将无法正常工作。我们基本上在做的是使用 angular 的脏检查循环来为我们做求和。

还要注意 watch listener 中 newVal 和 oldVal 的顺序。你的订单是错误的。

【讨论】:

  • 我看到的这个解决方案不支持将元素添加到“stuff”
  • @martinpaulucci 我已经提到过。 SEE:另外,如果 STUFF 中的对象数量发生变化,这将无法正常工作。
  • 这修正了原发帖者观看 'stuff.something' 而不是 'stuff[i].something' 的错误,并回答了本页标题中的问题:“Angular.js watch only on specific对象属性”。提到的与查看数组的各个元素有关的问题都是有效的,但这不是让我进入此页面的问题的一部分。谢谢。
【解决方案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

【讨论】:

    【解决方案4】:

    好吧,如果我知道了,您只想在内部对象更改时将 somethingsomethingelse 相加。如果更改发生在其中一个对象中,您不希望遍历所有其他内部对象。

    好吧,你的$watch 没有触发,因为没有stuff.property,也没有像stuff.*.something 这样的模式。

    如果您知道对象从阵列中推入或拉出的时刻,则可以在将每个对象插入阵列之前/之后分别应用$scope.$watch(object, function(){}, true)。如果您不知道这一刻,那么您将需要 $watch 整个数组,并且当发生更改时,运行所有取消注册函数并再次运行 $watch 它们,一个接一个。

    无论如何,现在浏览器中的循环非常快,除非您进行大量计算并且您拥有数百万个对象(这已经是内存问题),否则您可能会很好地使用它。因此,只有在计算量非常大的情况下,才需要单独$watch 它们,这可能会影响系统性能。

    【讨论】:

    • 我确定stuff 中的对象不会超过 100 个。所以你是说我应该只关注整个stuff 而不是按照@garanaj 的建议去做。
    • 在手表末尾添加 ,true 的问题是它会检查整个对象/数组。随着数组大小的增加,这将变得非常繁重。
    • 如果您知道数组何时发生变化,那么最好向它们单独添加$watch。无论如何,如果你的对象不是太密集,我看不到性能问题$watching 100 个项目。但是,如果您知道它何时发生变化,请坚持使用单独的手表。
    猜你喜欢
    • 2023-03-24
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 2015-09-03
    • 1970-01-01
    • 2020-01-15
    • 2021-12-10
    • 1970-01-01
    相关资源
    最近更新 更多