ShadowFlame
ShadowFlame

Reputation: 3278

angular multiple same directives in single controller

I'm building a webpage that uses Highcharts to visualize some data. To make it reusable, I've wrapped the chart that I want in a directive

'use strict';
angular.module('statisticsApp')
  .directive('cleanbarchart', function () {
    scope:{
      localdata:'@'
    }
    return {
      template: '<div></div>',
      restrict: 'E',
      link: function postLink(scope, element, iAttrs) {
          // console.log(iAttrs);
          // console.log(iAttrs);
          // var attrs = JSON.parse(iAttrs.id);
          var attrs = iAttrs;
          element.highcharts({
            chart: {
              type: 'column',
              width:1000,
              zoomType: 'x'
            },
            title: {
              text: scope.localdata[attrs.id].title //title
            },
            xAxis: {
              categories: scope.localdata[attrs.id].categories, crosshair: true

            },
            yAxis: {
              min: 0
            },
            tooltip: {
  //            headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
  //            pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
  //            '<td style="padding:0"><b>{point.y:.1f} mm</b></td></tr>',
  //            footerFormat: '</table>',
  //            shared: true,
  //            useHTML: true
            },
            plotOptions: {
  //            column: {
  //            pointPadding: 0.2,
  //            borderWidth: 0
  //          }
            },

            series: scope.localdata[attrs.id].series
          })
      }
    };
  });

In my controller, I use a service and a callback function to populate the localdata

angular.module('statisticsApp')
  .controller('AboutCtrl', function ($scope, HttpDataService) {

     function done(data){

       console.log(data);
       $scope.localdata['test2'] = data; //HttpDataService.getUniqueUsers() ;
     }

     $scope.localdata = {} ;
     HttpDataService.getUniqueUsers(done) ;
});

with a service that looks like this:

angular.module('statisticsApp')
  .service('HttpDataService', function($http, $q, baseRestPath) {
    // AngularJS will instantiate a singleton by calling "new" on this function
    return {
      getUniqueUsers: function (callback, periodicity) {
        var url = baseRestPath + '/sessions/uniqueUsers';
        console.log(url);
        var dates = [];
        var values = [];

        $http.get(url).then(
          function successCallback(response){
            var data = response.data;
            data.forEach(function(dataLine) {
              dates.push(dataLine[1]);
              values.push(dataLine[0]);
            })
            console.log(values);
            callback({title: 'Unique Users', categories:dates, 'series': [ {name: 'Alltime', data:values} ]  });
        //    return {'title': "Unique Users", 'categories':dates, 'series': [ {name: "Alltime", data:values} ]  }
          },function errorCallBack(response){
            //do nothing
          }
        );


//      return {'title': "Unique Users", 'categories':dates, 'series': [ {name: "Alltime", data:values} ]  }
      }
    }
  });

and finally, in my html i use the following code to call the directive

<cleanbarchart id="test2"></cleanbarchart>

while I'm certain that my service works, and returns the data correctly, I get the error

Cannot read property 'title' of undefined

I think it has to do with the asynchronous way that $http works, but I can't figure out how to make the directive watch on either scope.localdata or scope.localdata[attrs.id] which I have tried by wrapping the element.highcharts in the watch block

link: function postLink(scope, element, iAttrs) {
  scope.$watch('localdata',function(){
    element.highcharts.....
  }
}

or 

link: function postLink(scope, element, iAttrs) {
  scope.$watch('localdata[' + attrs.id + ']',function(){
    element.highcharts.....
  }
}

All help appreciated

Upvotes: 0

Views: 366

Answers (1)

Domas Mar
Domas Mar

Reputation: 1186

Firsty you need to change your service to return a promise instead of passing a callback to your service. If you open $http documentation you will see that $http.get returns HttpPromise object which you can later resolve.

After you done that you can pass promise to directive instead of data.

So instead of:

$scope.localdata = {} ;
HttpDataService.getUniqueUsers(done) ;

Change to:

$scope.localdataPromise = HttpDataService.getUniqueUsers();

And later in directive resolve it like that:

scope.localdataPromise.then(function (data) { /* resolve data and draw chart */ });

Upvotes: 2

Related Questions