1

I'm trying to access attr data defined by a controller in a custom directive's link function.

Here is some simple angular markup:

<div class='barChart'>
  {{vm.totals}}
  <bar-chart chart-data='vm.totals'></bar-chart
</div>

This is the directive defintion:

angular
    .module('app')
    .directive('barChart', [Callback])

function Callback() {
    return {
      restrict: 'E',
      replace: false,
      scope: {data: '=chartData'},
      link: (scope, el, attrs) => {
        console.log(scope);
        console.log(el);
        console.log(attrs.chartData);
      }
    }
}

When I log scope, I can see the data array in this object as expected, heres a picture: enter image description here

As you can see the data is the 10 item array at the bottom. The array also shows up in the browser, so the data is there. However, as soon as I change the console.log to log that property:

console.log(scope.data)

The value that gets printed is undefined. I'm trying to access the data in the link function so that I can use d3 to create a visualization. The data is there, but it's undefined as soon as I call .data on scope. Any ideas?

Andrew Kim
  • 3,145
  • 4
  • 22
  • 42

3 Answers3

1

Use $watch to log the data:

angular
    .module('app')
    .directive('barChart', [Callback])

function Callback() {
    return {
      restrict: 'E',
      replace: false,
      scope: {data: '=chartData'},
      link: (scope, el, attrs) => {
        console.log(scope);
        console.log(el);
        console.log(attrs.chartData);
        //USE $watch
        scope.$watch("data", function(value) {
          console.log(value);
        });
      }
    }
}
georgeawg
  • 48,608
  • 13
  • 72
  • 95
0

you can access vm.totals as scope variable but passed as attribute:

scope: {
  chartData: '='  //@ reads the attribute value
}

And in your html:

<bar-chart chart-data='vm.totals'></bar-chart>

Now in link function you can access it:

console.log(scope.chartData);

Note that this is one way binding, so if you need two way you need to use = instead.

Update:

If you are using async call you need to use two way binding or watch for the changes in your link function:

scope.$watch('chartData', function(newVal) {
    if(newVal) {  console.log(scope.chartData) }
}, true);

Note that since it is an array it is better to use collection watch (true as the last arg).

Yaser
  • 5,609
  • 1
  • 15
  • 27
  • that binds the string literal `'vm.totals'` to chartData not the data from the controller. – Andrew Kim Feb 09 '17 at 21:54
  • sorry forgot to put interpolation in html @AndrewKim check the update – Yaser Feb 09 '17 at 21:56
  • that .. sort of works. It makes it so i see a string of the array data. But i'm running into the same sort of problem, where i can see it fine when i `console.log(scope)`. As soon as I `console.log(scope.chartData)` it logs an empty string =( – Andrew Kim Feb 09 '17 at 22:02
  • it has to be that the data isn't there yet.. or something – Andrew Kim Feb 09 '17 at 22:06
  • I think it has to do with the async call I'm making to a csv file through a service to get the data. – Andrew Kim Feb 09 '17 at 22:09
  • that explains it, you need to use promise and resolve – Yaser Feb 09 '17 at 22:11
  • Yeah, thats gotta be it http://stackoverflow.com/questions/21177582/directive-is-being-rendered-before-promise-is-resolved is exactly what's happening to me. If you update your answer with what we've talked about I'll give ya the check. Thanks for the help! – Andrew Kim Feb 09 '17 at 22:15
0

use @ in the link function to have one way binding to the controller.

angular
    .module('app', [])
.controller('ctrl', function($scope){$scope.totals="1234";})
    .directive('barChart', [Callback])

function Callback() {
    return {
      restrict: 'E',
      replace: false,
      scope: {data: '@'},
      link: function(scope, el, attrs) {
        console.log(attrs.chartData);
      }
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class='barChart'>
  {{totals}}
  <bar-chart chart-data='{{totals}}'></bar-chart>
</div>
  </div>
Stark Buttowski
  • 1,799
  • 2
  • 10
  • 21