sir_thursday
sir_thursday

Reputation: 5409

Angular data issue- not sure how to troubleshoot

I have a controller (code below) that links to a d3-cloud directive and works perfectly. Data is added in the controller and passed to the directive.

myApp.controller('DownloadsCloudCtrl', ['$scope', 
                                        '$rootScope', 
                                        'requestService',
                                        '$cookieStore',
  function($scope, $rootScope, requestService, $cookieStore){
  $scope.d3Data = [
    {
        'kword': 'a',
        'count': 141658,
    },{
        'kword': 'b',
        'count': 105465,
    }
  ];
}]);

Now I'm trying to pull data from a JSON request service by switching my controller to the following code. When I do a console.log in the controller underneath the $scope.d3Data = data line, everything appears to be working properly (the proper data is returned).

However, something breaks when trying to link the controller to the directive, for some reason the directive is getting an undefined/null data set.

I'm wondering if the issue is in the order with which the code executes. Perhaps the controller tries to pass data to the directive before the JSON service has finished, thus resulting in no graph being drawn. Could this be happening, and if so, how can I go about fixing it?

myApp.controller('DownloadsCloudCtrl', ['$scope', 
                                        '$rootScope', 
                                        'requestService',
                                        '$cookieStore',
  function($scope, $rootScope, requestService, $cookieStore){
  $rootScope.$on('updateDashboard', function(event, month, year) {
    updateDashboard(month, year);
  });

  var updateDashboard = function(month, year) {
    requestService.getP2PKeywordData(month, year).then(function(data) {
      $scope.d3Data = data;
    });
  };

  updateDashboard($cookieStore.get('month'), $cookieStore.get('year'));
}]);

EDIT: Directive code:

myApp.directive('d3Cloud', ['$window', 
                            'd3Service', 
                            'd3Cloud', 
                            function($window, 
                                     d3Service, 
                                     d3Cloud) {
  return {

    // Restrict usage to element/attribute
    restrict: 'EA',

    // Manage scope properties
    scope: {

      // Bi-directional data binding
      data: '=',

      // Bind to DOM attribute
      label: '@'
    },

    // Link to DOM
    link: function(scope, element, attrs) {

      // Load d3 service
      d3Service.d3().then(function(d3) {

        // Re-render on window resize
        window.onresize = function() {
          scope.$apply();
        };

        // Call render function on window resize
        scope.$watch(function() {
          return angular.element($window)[0].innerWidth;
        }, function() {
          scope.render(scope.data);
        });

        // Render d3 chart
        scope.render = function(data) {

        // d3 specific appends... not important

HTML Code: (simple enough)

  <div class="col-md-6">
    <div class="module">
      <div class="inner-module" ng-controller="DownloadsCloudCtrl">
        <div class="module-graph">
          <d3-cloud data="d3Data"></d3-cloud>
        </div>
      </div>
    </div>
  </div>

Upvotes: 1

Views: 54

Answers (1)

link
link

Reputation: 2510

try adding a $scope.$apply() after $scope.d3Data = data;

$scope.d3Data = data;
$scope.$apply();

if this doesn't work, you can always pass a function down into the directive and set it to update the data and then manually call it from the controller:

so controller logic:

$scope.updateDirective = function () {}; // this will be overridden in directive

directive logic:

scope: {
  data: '=',
  update: '&updateDirective'
  label: '@'
}

scope.updateDirective = function () {
  scope.render(scope.data); // call to update function
};

markup:

  <div class="col-md-6">
    <div class="module">
      <div class="inner-module" ng-controller="DownloadsCloudCtrl">
        <div class="module-graph">
          <d3-cloud data="d3Data" update-directive="updateDirective"></d3-cloud>
        </div>
      </div>
    </div>
  </div>

Upvotes: 1

Related Questions