Angular $ watch not working

I use two $watches on my controller that should keep track of these two objects:

 $scope.gastos = { name: "Gastos mensuales", data: [0,0,0,0,0,0,0,0,0,0,0,0], labels: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"] }; $scope.ganancias = { name: "Ganancias mensuales", data: [0,0,0,0,0,0,0,0,0,0,0,0], labels: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"] }; 

Two charts (from Charts.js and angular -charts plugins) read data from them. I put diagrams in user directives that get data from an attribute and they work correctly.

The problem is that I want to create another graph that reads another object that is equal to them, but calculates it in this method:

 function calcularBeneficios(){ var data = []; for(var i=0;i<12;i++){ data[i] = $scope.ganancias.data[i] - $scope.gastos.data[i]; } console.log("FUNCTION DATA: "+data); return data; } 

This is a clock (I tried both to look at the variable object and object.data ):

 $scope.$watch("gastos", function(){ $scope.beneficios.data = calcularBeneficios(); console.log("SCOPE: "+$scope.beneficios.data); }); $scope.$watch("ganancias", function(){ $scope.beneficios.data = calcularBeneficios(); console.log("SCOPE: "+$scope.beneficios.data); }); 

This does not work. Do you see all console.logs ? I see only "SCOPE" console.log once (not even twice for ganancias ). When I change the data on some inputs attached to these two objects, everything works (diagrams are updated in real time), but the beneficios diagram does not work, since this clock simply does not work.

Am I doing something wrong in these two hours?

+5
source share
2 answers

The problem is that you are viewing top level objects gastos and ganancias . There are two potential problems:

  • As the docs for $ watch say, by default, the standard JavaScript inequality is used to determine if an object has changed ( x !== y ). Since the object itself is the same object, you just change the data inside it, it will always be true, so $watch does not start.

  • You can get around 1. by setting the objectEquality flag to true ( $scope.$watch('x', function(){}, true) ). In this case, a deep comparison takes place and differences in the data array should be identified. However, this greatly improves performance.

Since you just use the data array in each object, you can simply use $scope.$watchCollection in gastos.data . It is cleaner and faster.

Here is a working snippet demonstrating this:

 angular.module("myApp", []).controller('myCtrl', function($scope) { // same code function calcularBeneficios() { var data = []; for (var i = 0; i < 12; i++) { data[i] = $scope.ganancias.data[i] - $scope.gastos.data[i]; } console.log("FUNCTION DATA: " + data); return data; } $scope.beneficios = { name: "Beneficios mensuales", data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], labels: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" ] }; $scope.gastos = { name: "Gastos mensuales", data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], labels: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" ] }; $scope.ganancias = { name: "Ganancias mensuales", data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], labels: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" ] }; // watch the array collection in gastos.data $scope.$watchCollection("gastos.data", function() { $scope.beneficios.data = calcularBeneficios(); console.log("SCOPE: " + $scope.beneficios.data); }); // watch the array collection in ganancias.data $scope.$watchCollection("ganancias.data", function() { $scope.beneficios.data = calcularBeneficios(); console.log("SCOPE: " + $scope.beneficios.data); }); // testing functions $scope.changeGastos = function() { $scope.gastos.data[4] = 10; } $scope.changeGanancias = function() { $scope.ganancias.data[0] = 40; } }) 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script> <div ng-app="myApp" ng-controller="myCtrl"> <h3>beneficios.data</h3> <ul> <li ng-repeat="i in beneficios.data track by $index">{{i}}</li> </ul> <button ng-click="changeGastos()">Change Gastos</button> <button ng-click="changeGanancias()">Change Ganancias</button> </div> 
+5
source

Use $ watchCollection instead of $watch to view the collection.

Or you can also look like this:

 $scope.$watch("gastos + ganancias", function(){ $scope.beneficios.data = calcularBeneficios(); console.log("SCOPE: "+$scope.beneficios.data); }); 
+3
source

Source: https://habr.com/ru/post/1243830/


All Articles