Rumal
Rumal

Reputation: 1532

Create a highchart graphic using angular.js

I've spent the last 4 hours trying to make this thing work. I'm very new with angular.js, jquery, highcharts and all that stuff and I can't find the way to fix this.

What I'm trying to do is create a highchart graphic in a div. The json for the graphics came in the right way from the backend, so it isn't necessary to make any change to the json.

So, I've done the following:

First, in the html:

<div ng-controller="ChartController">
  <div class="chart-container" id="chartContainer"></div>
</div>

And in order to gather the data, I've made the following:

var termomether = angular.module('termomether', [ 'ngResource' ]);

termomether.factory('Chart', function($resource) {
  return $resource('/app/api/chart', {}, {
    query : {
      method : 'GET',
      params : {},
      isArray : true
    }
  });
});

termomether.controller('ChartController', function($scope, Chart) {
  $('#chartContainer').highcharts(Chart.query())
});

And the result is that the graphic is displayed, but empty. It has the size that I'm expected to have but doesn't have the data, it shows an empty white box.

If in this moment you are thinking that the problem is with the json, this maybe is going to make you think different. If I change the controller in the following form, the graphic is showed perfectly:

var termomether = angular.module('termomether', [ 'ngResource' ]);

termomether.controller('ChartController', function($scope, $http) {
  $http.get('api/chart').success(function(items) {
    $(function() {
      $('#chartContainer').highcharts(items)
    }); 
  });
});

Therefore... I don't have idea why it isn't working in the controller that use a factory and a resource

Upvotes: 1

Views: 6195

Answers (4)

Pablojim
Pablojim

Reputation: 8582

There's another directive here https://github.com/pablojim/highcharts-ng

Demo: http://jsfiddle.net/pablojim/Cp73s/

This allows you to create a highchart with the below html:

<highchart id="chart1" series="chart.series" title="chart.title" options="chart.options"></highchart>

In the above case chart.series is an array of javascript objects representing the series on the chart - these take standard Highcharts options. These are then watched by angularjs for any changes.

chart.options is the highcharts initalisation options - also watched for changes. Although changes to this recreate the entire chart.

chart.title is the highcharts title object - also watched for changes.

Upvotes: 0

Phil
Phil

Reputation: 2252

When I integrated HighCharts into a dashboard coded with AngularJS I found I had to use $timeout(). There's no delay set since I just want the render to be put on the thread stack and executed as soon as AngularJS $digest is finished. Something like this :

$timeout(function() { var chart = new Highcharts.Chart(newSettings); });

Upvotes: 0

wmluke
wmluke

Reputation: 309

DOM scripting is discouraged within Angular Controllers, but fear not this is where Angular Directives shine.

Try something like...

JS*:

(function () {

    function SomeController($scope, $http) {
        // Load your chart data
        $http.get('/chart/123').success(function (data) {
            $scope.chartOpts = data;
        });
    }

    function highChartDirective() {
        return function (scope, $element, attr) {
            // Create the chart when the scope variable specified by the value of the `options` attribute changes
            // - If `options` is updated more than once, then you may have to destroy/reset the highchart instance.
            scope.$watch(attr.options, function (options) {
                if (options) {
                    $element.highcharts(options);
                }
            });
        };
    }

    // Note, controllers and directives should be defined in separate modules.
    angular.module('app', [])
        .controller('SomeController', ['$scope', '$http', SomeController])
        .directive('highChart', [highChartDirective]);
}());

HTML*:

<div ng-controller="SomeController">
    <div high-chart options="chartOpts"></div>
</div>

Things get more complicated if you chart is interactive. You'll have to use Scope.$apply and possibly a Directive Definition Object to "set up bi-directional binding between a local scope property and the parent scope property of name defined via the value of the attr attribute".

*Code not tested

Upvotes: 0

Chandermani
Chandermani

Reputation: 42669

The query method on resource is async in nature. You need to do data bind in the callback. So the code becomes

Chart.query(function(data) {
$('#chartContainer').highcharts(data);
});

Said that, this is not the angular way to achieve the result. Controllers are not used to manipulate view.

You should look at angularjs directives to achieve this functionality. I found one such directive here https://github.com/rootux/angular-highcharts-directive

Upvotes: 2

Related Questions