37

I am new to Angular and Flot, but am experienced with Jquery and Javascript. I am a bit confused about how to go about binding a Flot chart to Angular data models, since Flot is a JQuery plugin. I've searched around, but haven't been able to find an example.

I would also be happy to use highcharts, google-charts, or any other charting solution.

JBCP
  • 13,109
  • 9
  • 73
  • 111

2 Answers2

67

Since charting involves heavy DOM manipulation, directives are the way to go.

Data can be kept in the Controller

App.controller('Ctrl', function($scope) {
    $scope.data = [[[0, 1], [1, 5], [2, 2]]];
});

And you can create a custom HTML tag1 specifying the model you want to get data from

 <chart ng-model='data'></chart>

which angular can compile through a directive

App.directive('chart', function() {
    return {
        restrict: 'E',
        link: function(scope, elem, attrs) {
            var data = scope[attrs.ngModel];
            $.plot(elem, data, {});
            elem.show();
        }
    };
});

Example here.

This process is similar for most plugins that modify the DOM.

-*-

Also, you can watch for changes in the chart's underlying data and redraw it, so this way you can grab data through the $http service from your controller and update the view automatically. This can be achieved by modifying the linking function in the directive definition object

   var chart = null,
       opts  = { };

    scope.$watch(attrs.ngModel, function(v){
        if(!chart){
            chart = $.plot(elem, v , opts);
            elem.show();
        }else{
            chart.setData(v);
            chart.setupGrid();
            chart.draw();
        }
    });

Notice the usage of Flot's API within the directive to achieve what we want.

Here the full example


1 Can be an attribute too.

Trufa
  • 39,971
  • 43
  • 126
  • 190
jaime
  • 41,961
  • 10
  • 82
  • 52
  • 2
    This was very informative. I had to learn a bit more about Angular's API to get it working across two separate js files (to keep the directive and the controller separate). I found one problem, which is that if you watch 'data', you have tied your directive to the model's name. A better solution is to use 'scope.$watch(attrs.ngModel',....). I have updated the fiddle here: http://jsfiddle.net/TDwGF/3/ – JBCP Oct 28 '12 at 02:21
  • 1
    For new Angular users: To use this directive as an attribute, you need to change the line that says "restrict: 'E'" to "restrict: 'EA'". E is 'Element', A is 'Attribute'. – JBCP Nov 06 '12 at 03:46
  • 1
    I suggest to use var data = scope.$eval(attrs.ngModel) in the first fiddle because then your ng-model can be "charts.exchangerates.eur2usd". In the second fiddle I would use a deep watch to see changes inside the data object. Here is a fiddle that is not broken due the MIME-Change in github: http://jsfiddle.net/dWDDp/ –  Mar 06 '14 at 19:10
  • Examples where not working I updated them with a cdn link instead of github user content. – Trufa Sep 29 '14 at 09:11
  • Hello can you please see my question http://stackoverflow.com/questions/37256487/i-want-to-change-the-chart-for-each-city-or-subcity-selected – Abderrahim May 17 '16 at 13:10
1

To use jQuery plugins with angularJS, you have to wrap them in directives, you can find some exemples of jQuery plugins directives by reading the source code of angularUI directives: https://github.com/angular-ui/angular-ui/tree/master/modules/directives

Guillaume86
  • 14,341
  • 4
  • 53
  • 53