Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular $watch doesn't get triggered

I'm trying to write a directive for drawing barcharts, and I'd like it to redraw the chart every time the data changes. I currently have this:

/* This directive will create a bar chart based on a dataTable. 
 * It expects the first column of the data table to contain the labels.
 * If more than 2 columns (labels plus more than one value) are supplied,
 * all bars generated by values in one row will be grouped together, making 
 * an easy visual comparison (benchmark).
 * If the option overlay is supplied, the odd value columns will be drawn
 * underneath the even values (Ex [label, col1, col2, col3, col4], with overlay = true will result 
 * in col1 and col3 to be drawn underneath col2 and col4
 */


angular.module('kapstok').directive('nBarChart', ['$window', '$location', '$parse', '$timeout', 
    function($window, $location, $parse, $timeout){
  return{
    restrict: 'E',
    scope: true,
    link: function(scope, elm, attrs){

      // Read all the different parameters givin in the directive declaration.
      // If options are not given, they are replaced by their default values.
      var dataGetter        = $parse(attrs.data);
      var data = dataGetter(scope) || undefined;
      if(!data){
        throw Error("No (valid) data source specified!");
      }



          // Redraw the table once the table gets updated. However, usually multiple elements
      // of the table will be updated at the same time, while the watch will get triggered 
      // at each update. To prevent this, we give it a timeout of half a second,
      // allowing all the updates to be applied before the table is redrawn.
      scope.$watch(function(){ return data.getVersion(); }, $timeout(drawChart, 500));

Then, in my controller I do:

controlmodule.controller('PrefscanController',['$http', '$scope', 'DataTable', function($http, $scope, DataTable){
  $scope.myData = new DataTable();
  $scope.myData.addColumn("string", "label");
  $scope.myData.addColumn("number", "survey");
  $scope.myData.addColumn("number", "benchmark");
  $scope.myData.addColumn("number", "break-it");

  $scope.myData.addRow(['test', 20, 10, 4]);
  $scope.myData.addRow(['test2', 42, 13, 2]);


  $scope.hideBenchmark = function(){
    console.log("myData.version = ", $scope.myData.getVersion());
    $scope.myData.hideColumn(2);
    console.log("myData.version = ", $scope.myData.getVersion());
  }

In all the functions from dataTable, whenever anything is changed a property called 'version' is incremented, which is what I want the $watch to look at.

In my template I then have a button with an ng-click, which calls the hideBenchmark function. This function does get called, the dataTable version is updated, but whatever I try, the watch will not get triggered.

I've tried called $scope.$appy()/$scope.$digest() in my hideBenchmark function, tried adding 'true' to the watch (looking for object inequality), tried watching 'attrs.data', 'data.version' and none of it seem to trigger the watch! I know I can create another variable on the scope independent from this data one, watch that and change it every time I change the data, but that seems ugly and unnecessary.

Does anybody know WHY the watch doesn't get triggered, and how I can get it to do what I want?

Regards,

Linus

like image 891
Linus Avatar asked Mar 07 '26 17:03

Linus


1 Answers

As suggested by Sunil, you should put it in the scope:

scope: {
    data: '='
} 

Because if you do not do it, the data is not updated within the directive.

Here the fiddle: http://jsfiddle.net/0t4z02yw/2/

like image 149
Michael Avatar answered Mar 10 '26 08:03

Michael



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!