There is a directive:

angular.module('analyticsMenu').directive('chartJs', ['$timeout', function($timeout) { return { restrict: 'E', scope: { type: '=', width: '=', height: '=', data: '=', options: '=' }, templateUrl: 'analytics-menu/chart-js/chart-js.template.html', link: function($scope, $element, $attr) { var newChart = function() { var ctx = $element.find('canvas')[0]; var chart = new Chart(ctx, { type: $scope.type, data: $scope.data, options: $scope.options }); }; var watchData = function() { return JSON.stringify($scope.data); }; $scope.$watch('watchData', updateWhenDataChange, true); var updateWhenDataChange = function(newVal, oldVal) { console.log(123); } $timeout(newChart, 0); } } }]); 

When changing the data attribute (or rather, when changing any of the parameters of the objects that I pass to the directive as a parameter), I need to redraw the graph.

At first, I just tried to write:

 $scope.$watch('data', updateWhenDataChange, true); 

But this led to an error:

angular.js: 13920 RangeError: Maximum call stack size exceeded

  • one
    $watch executes the string passed to it in the context of the Osprey for which it is called, watchData _ is not in the Osprey, respectively $scope.watchData scope.watchData never changes and always _undefiend . If you add a working example, you can see what was wrong with data - Grundy
  • one
    Why do you need $ timeout down there? - Grundy
  • one
    and it is still possible that the value of undefined is substituted into $ watch and not the function that is assigned to the variable later - Grundy
  • one
    therefore, a minimal reproducible example is needed - Grundy
  • one

2 answers 2

Having talked in a chat with @Grundy, he suggested to me that it was necessary to deal with this problem (initially I tried to “get around” it). Today, I still could deal with it.

The essence of the problem was that the Chart.js library wrote its "system" data to objects whose state changes I was checking. Because of this, the data change handler function was constantly called.

How did I solve the problem? I create a copy of the array with the data WITHOUT the "_meta" property, in which the data of Chart.js are written. I check only the change of this data. Here is the code:

 'use strict'; angular.module('analyticsMenu').directive('chartJs', ['$timeout', function($timeout) { return { restrict: 'E', scope: { type: '=', width: '=', height: '=', data: '=', options: '=' }, templateUrl: 'analytics-menu/chart-js/chart-js.template.html', link: function($scope, $element, $attr) { var canvas = $element.find('canvas')[0]; var chart = null; var newChart = function() { if (chart === null) { chart = new Chart(canvas, { type: $scope.type, data: $scope.data, options: $scope.options }); } else { chart.update(); } }; var without = function without(obj, keys) { if (obj === null || typeof obj !== 'object') { return obj; } var temp = obj.constructor(); for (var key in obj) { if (key != '_meta') { temp[key] = without(obj[key], keys); } } return temp; }; var watchComplexNode = function() { return without($scope.data, ['_meta']); }; $scope.$watch(watchComplexNode, function () { newChart(); }, true); } } }]); 

I also recommend reading this article .

P.S. Thanks again for the help @Grundy!

     angular.module('app', []) .controller('MainController', ['$scope', function($scope){ var watchData = function() { return JSON.stringify($scope.data); }; var updateWhenDataChange = function(newVal, oldVal) { console.log(123); } $scope.$watch('watchData', updateWhenDataChange, true); }]) 
     <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <main ng-app='app' ng-controller="MainController as main"></main> 

    Declare updateWhenDataChange first, and then call it.

    • one
      actually doesn't quite work that way, since watchData in $ scope is not added - Grundy
    • added code. Works without $ scope - alexander
    • one
      now try changing the value in $ scope.data - Grundy
    • one
      watchData is a function that returns the serialized value of $ scope.data . Actually for the sake of what the author of the question did it - to track the changes in this field. The above code does not do this; it tracks the change in $ scope.watchData which is always undefined - Grundy
    • one
      in spite of the fact that the data changes , this problem just does not solve it. - Grundy