4

I've recently started using NVD3's great angular directives for constructing D3 charts. Indeed they are slick. However I'm having a lot of difficulties with callbacks. Callbacks work well enough when I add them using nv.addGraph(), like in Alex's answer and in the examples page. I've also had varying success with other suggestions in these SO answers. But to make it easier for other junior programmers in my company, I would like to use an HTML directive like those shown on the examples on github. Something like this:

<nvd3-multi-bar-chart
   data="monthData"
   id="monthDataChart"
   ... other properties ...
   callback="monthCallback">
   <svg></svg>
</nvd3-multi-bar-chart>

The function in my scope called monthCallback attempts to attach attributes, such as titles, and events, such as click, to each .nv-bar in the chart. The problem is that the chart starts to render before the data returns from the ajax request, and so monthCallback is fired before there are any .nv-bar on the page. (Note: it doesn't seem to make a difference whether or not the callback is declared with parentheses, i.e. callback="monthCallback" vs. callback="monthCallback()")

I considered using the workaround by liptga, or DavidSouther's answer, but linking the callback to the transition seemed the wrong way to address this problem. Any other suggestions for getting the callback to fire at the right time, using the HTML directive?

Community
  • 1
  • 1
moshefnord
  • 164
  • 2
  • 8
  • Should have mentioned, another key advantage of using the directives is to utilize Angular's binding and automatic updates. Using nv-addGraph() eliminates this agility. – moshefnord May 29 '14 at 08:16

2 Answers2

5

You can also try angular-nvd3 directive. It completely operates with charts via json, and you can also access to the full nvd3 core api.

In your case, you need to somehow refresh the chart.

1). One can use an api attribute of this directive like:

//in html
<nvd3 options="options" data="data" api="api"></nvd3>  

and then in controller you can completely refresh directive anywhere using:

//javascript
$scope.api.refresh();

2). Another approach is to just make your chart hidden/visible, using config attribute and varying visible option like:

<nvd3 options="options" data="data" config="{ visible: false }"></nvd3> 

For example, if there is no data yet, set visible: false. While data is returned, set visible: true. See live example below.

3). And the simplest way is to just change your data, and directive automatically will be refreshed with new data:

//javascript
$scope.data = newData;
$scope.$apply();  //sometimes you need to refresh the scope

As for your case with ajax it can look something like:

//ajax request; in the live example below I use timeout 
$http.get("/some_url/")
     .success(function(data){
          $scope.data = data;
          $scope.$apply();
          //chart will render after the data returns
     })

Callback function is defined as any other options:

//javascript, in controller
$scope.options = {
    ..., //any other options
    callback: function(){
        d3.selectAll(".nv-bar").on('click', function(){
            alert("Hi, I'm callback!");
        });
    }
}

So it will be fired after chart renders, and after data is returned.

See live example. (updated with callback)

krispo
  • 526
  • 1
  • 4
  • 11
  • Haven't tried it yet but this looks similar, at least in name, to the Angularjs-nvd3-directives [link](http://cmaurer.github.io/angularjs-nvd3-directives/multi.bar.chart.html) but with a fancier website - is one built on the other? The idea to use an api directive is interesting as I haven't done that before. But how does any of this help with the callback? – moshefnord Jun 11 '14 at 07:29
  • Is it just your timeout on the clicks that would provide me the mechanism to bind events to chart elements after the chart is created, or is there something more at play here? – moshefnord Jun 11 '14 at 07:39
  • First, angular-nvd3 project has appeared recently, and has a fundamental difference from the others in the base approach it is created (compare source). This directive provides a two-way binding mechanism for all chart options over the full nvd3 core as well as chart data. It allows you to interactively customize chart options or data from the controller on the fly via JSON. This is the key question why yet another directive was developed. – krispo Jun 11 '14 at 19:24
  • Second, I'm sorry, the callback mechanism was actually missed and thank you for pointing to that. Now it is fixed! I've updated answer with callback. – krispo Jun 11 '14 at 19:25
  • 1
    I can't see the live example...I think the link pointing to plunkr is wrong – ackuser Nov 11 '15 at 09:25
0

Not sure if that much related to the question, but ended here by searching callback firing too soon. I had similar problem with the Angular directive and Callback was firing too fast, I just added a simple if statement to see if the item I am trying to access is ready. Like this:

    callback(chart) {
      if (chart && chart.interactiveLayer) {
      // do something
Shnigi
  • 972
  • 9
  • 19