Angular.js смотреть только на определенное свойство объекта - программирование
Подтвердить что ты не робот

Angular.js смотреть только на определенное свойство объекта

В принципе, я хочу это http://plnkr.co/edit/3yfXbo1c0llO40HZ8WNP?p=preview, но часы не срабатывают, когда я что-то меняю.

Я знаю, что это сработало бы

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

}, true);

Но так как я хочу сделать некоторые подсчеты внутри часов, и я не хочу излишне цитировать или перевычислять значения, которые не менялись.

//edit - обратите внимание, что пример plnkr - это просто извлечение из реального приложения, где вы можете добавлять и удалять строки и многое другое, например, изменять общее число (сумму somethings и somethingelses) с другого ввода вне ng-repeat.

4b9b3361

Ответ 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

Ответ 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, чтобы сделать наше суммирование для нас.

Также обратите внимание на порядок newVal и oldVal в прослушивателе часов. Ваш заказ неправильный.

Ответ 3

Так как $watch() принимает выражение angular, вы можете использовать пользовательскую функцию watcher. В вашем случае самый простой способ наблюдать за изменениями - это просто добавить все интересующие вас поля, а затем вернуть один номер, который хорош и эффективен для angular, и ваша сумма будет готова к рендерингу.

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

Хорошо, если бы я получил его, вы просто хотите суммировать something с somethingelse внутренних объектов, когда они меняются. И вы не хотите прокручивать все другие внутренние объекты, если изменение находится в одном из них.

Ну, ваш $watch не стреляет, потому что нет stuff.property, и нет таких шаблонов, как stuff.*.something.

Если вы знаете момент, когда объекты выталкиваются или вытягиваются из массива, вы можете применять отдельно $scope.$watch(object, function(){}, true) до/после вставки каждого из них в массив. Если вы не знаете этого момента, вам понадобится $watch весь массив, и когда произойдет какое-либо изменение, запустите все функции дерегистрации и $watch все снова, поочередно.

В любом случае, цикл в современных браузерах довольно быстрый, и, кроме того, что вы делаете тяжелые вычисления, и у вас есть миллионы объектов (что уже было проблемой памяти), вы, вероятно, будете довольны этим. Таким образом, усилие для $watch их всех отдельно необходимо только в том случае, если у вас действительно тяжелые вычисления, которые могут включать в себя производительность системы.