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.
Ответы
Ответ 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)
, если ваши объекты более сложны, чем вы показали здесь.
Ответ 4
Хорошо, если бы я получил его, вы просто хотите суммировать something
с somethingelse
внутренних объектов, когда они меняются. И вы не хотите прокручивать все другие внутренние объекты, если изменение находится в одном из них.
Ну, ваш $watch
не стреляет, потому что нет stuff.property
, и нет таких шаблонов, как stuff.*.something
.
Если вы знаете момент, когда объекты выталкиваются или вытягиваются из массива, вы можете применять отдельно $scope.$watch(object, function(){}, true)
до/после вставки каждого из них в массив. Если вы не знаете этого момента, вам понадобится $watch
весь массив, и когда произойдет какое-либо изменение, запустите все функции дерегистрации и $watch
все снова, поочередно.
В любом случае, цикл в современных браузерах довольно быстрый, и, кроме того, что вы делаете тяжелые вычисления, и у вас есть миллионы объектов (что уже было проблемой памяти), вы, вероятно, будете довольны этим. Таким образом, усилие для $watch
их всех отдельно необходимо только в том случае, если у вас действительно тяжелые вычисления, которые могут включать в себя производительность системы.