In my AngularJS app I'm using the custom directive 'highcharts-ng' to generate charts. I have a JSFiddle that creates a stock chart and works properly with scope-defined data, but throws an error when data are being fetched with $resource calls to a REST API (through a Factory):

JSFiddle that works with scope-defined data


For the REST-driven version, I have the following function for querying data:

function getData(start, end) {
    return measurementsFactory
        .getMeasurements(start, end)
            .then(function(response) {
                return response.data;
            });
    }

REST-driven initChart function then becomes:

function initChart() {
    vm.chartConfig.title.text = 'New Title';

    var yAxis = inityAxis();
    vm.chartConfig.yAxis = yAxis;

    getData(moment(0).valueOf(), moment().valueOf()).then(function(data) {
        var series = initSeries(data);
        vm.chartConfig.series = series;
        vm.chartConfig.navigator.series = series;
    });
}

where the returned 'data' array is identical to the 'vm.testData array' in the JSFiddle. The chart loads without any errors and the result looks exactly the same as in the scope-defined data JSFiddle.

The REST-driven version of afterSetExtremes:

function afterSetExtremes(e) {
    if (e.trigger != undefined) {
        getData(Math.round(e.min), Math.round(e.max)).then(function(data) {
            var series = initSeries(data);
            vm.chartConfig.series = series;
        });
    }
}

The Problem

Whenever I try to set the time range using the buttons, input or the navigator, I get the following error:

TypeError: Cannot read property 'hoverSeries' of undefined
    at p.destroy (highstock.js:305)
    at p.d.destroy (highstock.js:429)
    at b (highstock.js:334)
    at a.fireEvent (highstock.js:30)
    at p.remove (highstock.js:334)
    at p.<anonymous> (highstock.js:486)
    at a.fireEvent (highstock.js:30)
    at p.remove (highstock.js:334)
    at HighChartNGController.$doCheck (highcharts-ng.js:54)
    at angular.js:9605

and the navigator series disappears. I'm not sure how to proceed from here.


Edit 1 (2017-09-01)

Here's a JSFiddle that fetches data from a REST service that simulates the real app-server setup

However, now I'm getting a different error when the chart is being drawn.

TypeError: Cannot read property 'breaks' of undefined
    at Navigator.init (https://code.highcharts.com/stock/highstock.src.js:35910:50)
    at Navigator.update (https://code.highcharts.com/stock/highstock.src.js:35381:22)
    at H.Chart.<anonymous> (https://code.highcharts.com/stock/highstock.src.js:38494:32)
    at H.Chart.obj.(anonymous function) [as update] (https://code.highcharts.com/stock/highstock.src.js:928:28)
    at HighChartNGController.$doCheck (https://rawgit.com/pablojim/highcharts-ng/master/src/highcharts-ng.js:119:20)
    at https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js:9873:68
    at Scope.$digest (https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js:18202:34)
    at Scope.$apply (https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js:18480:24)
    at done (https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js:12501:47)
    at completeRequest (https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js:12727:7)

Edit 2 (2017-09-05)

Now I have this pure Highcharts JSFiddle that is working as intended (with some slight modifications to the axes).

1

There are 1 answers

1
Maxime On

After some researches I finally found the problem:

It comes from the axis that are inexistant at the moment you set the chart bounds. To get rid of this issue, you need to refresh the chart after the new data are set.

The culprit is the afterSetExtremes function. It doesn't alert the view something changed, so it didn't redraw the chart but its config object is still updated and the xAxis coordinates aren't good anymore.

I was running into this error : https://www.highcharts.com/errors/18

So here is the updated afterSetExtremes function:

function afterSetExtremes(e, scope) {
 if (e.trigger != undefined) {
   getData(Math.round(e.min), Math.round(e.max)).then(function(data) {
     var series = initSeries(data);
     scope.$apply(function() {
       scope.chartConfig.series = series;
     });
   });
 }
}

And how it's called into the chart config object (note that the scope is given to the function in order to call $apply() on it:

xAxis: [{
  type: 'datetime',
  minRange: 3600 * 1000,
  events: {
    afterSetExtremes: afterSetExtremes(vm)
  }
}],

I also add this function to the Highcharts config object because ng-highcharts is known to screw the charts redraw up:

func: function(chart) {
  vm.$evalAsync(function() {
    chart.reflow();
  });
}

Finally, here is your working fiddle.