0

I am trying to implement the HighStock Lazy Loading Sample in my angular-cli application ( https://www.highcharts.com/stock/demo/lazy-loading ). The sample, when the page loads, make a request to an webapi and retrives the data for the chart. That works fine.

The chart has a date range refiner control that allows you to select a new data range. This creates a new request to the webapi. This is the part I cannot get to work. enter image description here

When I select a new data range, the "afterSetExtremes" event is being triggered on the chart control. That event is being triggered just fine, but eventually results in the error:

core.js:9110 ERROR TypeError: this.getChartData is not a function
    at I.afterSetExtremes (candlestick-and-volume.component.ts:92)
    at highcharts.js:32
    at a.fireEvent (highcharts.js:32)
    at highcharts.js:272
    at highcharts.js:273
    at Array.forEach (<anonymous>)
    at a.Chart.redraw (highcharts.js:273)
    at I.<anonymous> (highcharts.js:162)
    at a.fireEvent (highcharts.js:32)
    at I.setExtremes (highcharts.js:162)

Let me take you through the flow from selecting a new date range until the error.

Here is the snippet of the chart configurations where the event is being defined.

xAxis: {
    events: {
      afterSetExtremes: this.afterSetExtremes
    },
    minRange: 3600 * 1000 // one hour
  },

enter image description here

Here is the "afterSetExtremes" function:

afterSetExtremes(e: { min: number; max: number }) {
    console.log('Here we should load data. min: ' + e.min + ' max: ' + e.max);    
     this.getChartData(e.min, e.max);     
}

this is my getChartData function

getChartData(min?: number, max?: number) {
    this.apiService
  .getChartData({ correlationId: this.correlationId, startdateAsUnixTimeStamp: -1, enddateAsUnixTimeStamp: -1 })
  .pipe(
    finalize(() => {
      if (this.chartData.length > 0) {
        this.updateChart();
      }
    })
  )
  .subscribe(response => {
    this.chartData = response.ChartData;
  });
}

This is the complete code off my component

import { StockChart } from 'angular-highcharts';
import { ApiService } from '@app/services/snakeApi/api.service';
import { ActivatedRoute } from '@angular/router';
import { finalize } from 'rxjs/operators';
import { ChartData } from '@app/model/ChartData';
import { Options } from 'highcharts/highstock';

@Component({
  selector: 'app-candlestick-and-volume',
  templateUrl: './candlestick-and-volume.component.html',
  styleUrls: ['./candlestick-and-volume.component.scss']
})
export class CandlestickAndVolumeComponent implements OnInit {
  stock: StockChart;
  chartData: Array<ChartData> = new Array<ChartData>();
  sub: any;
  correlationId: string;
  chartOptions: Options;
  candleStickDataArray: any = [];
  volumeDataArray: any = [];
  indicatorUpperDataArray: any = [];
  indicatorLowerDataArray: any = [];

  constructor(private apiService: ApiService, private activateRoute: ActivatedRoute) {
    this.sub = this.activateRoute.params.subscribe(params => {
      this.correlationId = params.correlationId;

      this.getChartData();
    });
  }

  getChartData(min?: number, max?: number) {
    this.apiService
      .getChartData({ correlationId: this.correlationId, startdateAsUnixTimeStamp: -1, enddateAsUnixTimeStamp: -1 })
      .pipe(
        finalize(() => {
          if (this.chartData.length > 0) {
            this.updateChart();
          }
        })
      )
      .subscribe(response => {
        this.chartData = response.ChartData;
      });
  }

  updateChart() {
    const dataLength = this.chartData.length;

    // set the allowed units for data grouping
    let groupingUnits = [],
      i = 0;

    for (i; i < dataLength; i += 1) {
      this.candleStickDataArray.push([
        this.chartData[i].Date, // the date
        this.chartData[i].Open, // open
        this.chartData[i].High, // high
        this.chartData[i].Low, // low
        this.chartData[i].Close // close
      ]);

      this.volumeDataArray.push([
        this.chartData[i].Date, // the date
        this.chartData[i].Volume // the volume
      ]);

      this.indicatorUpperDataArray.push([
        this.chartData[i].Date, // the date
        this.chartData[i].IndicatorUpper //  the upper indicator
      ]);

      this.indicatorLowerDataArray.push([
        this.chartData[i].Date, // the date
        this.chartData[i].IndicatorLower //  the lower indicator
      ]);
    }

    // Add a null value for the end date
    var endDate = this.chartData[dataLength - 1].Date;
    this.chartData = [].concat(this.chartData, [[endDate, null, null, null, null]]);
    console.log('EndData: ' + endDate);

    this.stock = new StockChart(this.chartOptions);
  }

  afterSetExtremes(e: { min: number; max: number }) {
    console.log('Here we should load data. min: ' + e.min + ' max: ' + e.max);    
     this.getChartData(e.min, e.max);     
  }

  ngOnInit() {
    this.chartOptions = {
      rangeSelector: {
        buttons: [
          {
            type: 'hour',
            count: 1,
            text: '1h'
          },
          {
            type: 'day',
            count: 1,
            text: '1d'
          },
          {
            type: 'week',
            count: 1,
            text: '1w'
          },
          {
            type: 'month',
            count: 1,
            text: '1m'
          },
          {
            type: 'year',
            count: 1,
            text: '1y'
          },
          {
            type: 'all',
            text: 'All'
          }
        ],
        inputEnabled: false, // it supports only days
        selected: 0 // all
      },
      title: {
        text: 'AAPL Historical'
      },

      navigator: {
        adaptToUpdatedData: false,
        series: {
          data: this.chartData
        }
      },

      scrollbar: {
        liveRedraw: false
      },

      xAxis: {
        events: {
          afterSetExtremes: this.afterSetExtremes
        },
        minRange: 3600 * 1000 // one hour
      },

      yAxis: [
        {
          labels: {
            align: 'right',
            x: -3
          },
          title: {
            text: 'OHLC'
          },
          height: '80%',
          lineWidth: 1,
          resize: {
            enabled: true
          }
        },
        {
          labels: {
            align: 'right',
            x: -3
          },
          title: {
            text: 'Volume'
          },
          top: '90%',
          height: '10%',
          offset: 0,
          lineWidth: 1
        }
      ],

      series: [
        {
          type: 'candlestick',
          zoomType: 'x',
          name: 'AAPL',
          id: 'aapl',
          data: this.candleStickDataArray,
          dataGrouping: {
            enabled: false
          }
        },
        {
          type: 'column',
          zoomType: 'x',
          name: 'Volume',
          data: this.volumeDataArray,
          yAxis: 1,
          dataGrouping: {
            enabled: false
          }
        },
        {
          type: 'spline',
          zoomType: 'x',
          name: 'indicatorUpper',
          id: 'indicatorUpper',
          data: this.indicatorUpperDataArray,
          dataGrouping: {
            enabled: false
          }
        },
        {
          type: 'spline',
          zoomType: 'x',
          name: 'indicatorLower',
          id: 'indicatorLower',
          data: this.indicatorLowerDataArray,
          dataGrouping: {
            enabled: false
          }
        }        
      ]
    };
  }
}

enter image description here

Tony
  • 1,394
  • 5
  • 22
  • 48
  • Looks like the chart is being destroyed and build anew in the middle of the axis event, so this might be causing the error. Please create a live demo for the problem. Have you tried just updating the series data as in the original JS demo? – Kacper Madej Jan 17 '20 at 16:05
  • Thank you Kacper. I have isolated the problem and created a new question. https://stackoverflow.com/questions/59806505/angular-cli-this-resolves-to-a-child-component-instead-of-the-main-component How would you suggest me to make a live demo? Are you aware of aplunker/codepen type of service i can use for this? – Tony Jan 19 '20 at 02:04
  • I know https://codesandbox.io/ and https://stackblitz.com/ – Kacper Madej Jan 21 '20 at 10:32

0 Answers0