问题
I am trying to implement this chart component https://www.highcharts.com/stock/demo/candlestick-and-volume in my angular-cli app. The chart is getting its data from a webapi. It allows you to specify a new date range. When you do that an event is being triggered and in that event you can call your webapi service and requst new data.
You configure the chart by passing in some options in the contructor
this.chart = new StockChart(this.chartOptions);
One of the options you can set is an event that gets fired when you select a new date range
this.chartOptions = {
...
xAxis: {
events: {
afterSetExtremes: this.afterSetExtremes
},
minRange: 3600 * 1000 // one hour
},
...
}
So when you select a new date range, this function is being called
afterSetExtremes(e: { min: number; max: number }) {
console.log('Here we should load data. min: ' + e.min + ' max: ' + e.max);
}
It is in that function my troubles are because 'this' resolves to the chart control and not my component so I cannot not access my WebApi Service, httpclient or other methods, property in my component.
If I inside the afterSetExtremes function do a
console.log(this);
i get the chart and not the component as I would have expected
if i console.log(this) from my constructor i get the expected value, my component and access to my api service
constructor(private apiService: ApiService, private activateRoute: ActivatedRoute) {
...
console.log(this);
}
**All this results in that I cannot call my service and get the updated data as I am unable to reference my apiservice and/or my getChartData function **
Here are the complete code for my component
import { Component, OnInit } from '@angular/core';
import { StockChart } from 'angular-highcharts';
import { ApiService } from '@app/services/snakeApi/api.service';
import { ActivatedRoute } from '@angular/router';
import { finalize } from 'rxjs/operators';
import { ChartDataCandleStick, ChartDataIndicator } 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 {
chart: StockChart;
chartDataCandleStick: Array<ChartDataCandleStick> = new Array<ChartDataCandleStick>();
chartDataIndicatorUpper: Array<ChartDataIndicator> = new Array<ChartDataIndicator>();
chartDataIndicatorLower: Array<ChartDataIndicator> = new Array<ChartDataIndicator>();
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(-1, -1);
console.log(this);
});
}
getChartData(min: number, max: number) {
this.apiService
.getChartData({ correlationId: this.correlationId, startdateAsUnixTimeStamp: min, enddateAsUnixTimeStamp: max })
.pipe(
finalize(() => {
if (this.chartDataCandleStick.length > 0) {
this.updateChart();
}
})
)
.subscribe(response => {
this.chartDataCandleStick = response.ChartDataCandleStick;
this.chartDataIndicatorUpper = response.ChartDataIndicatorUpper;
this.chartDataIndicatorLower = response.ChartDataIndicatorLower;
});
}
updateChart() {
const candleStickDataLength = this.chartDataCandleStick.length;
const indicatorUpperDataLength = this.chartDataIndicatorUpper.length;
const indicatorLowerDataLength = this.chartDataIndicatorLower.length;
// set the allowed units for data grouping
let groupingUnits = [],
i = 0;
for (i; i < candleStickDataLength; i += 1) {
this.candleStickDataArray.push([
this.chartDataCandleStick[i].Date, // the date
this.chartDataCandleStick[i].Open, // open
this.chartDataCandleStick[i].High, // high
this.chartDataCandleStick[i].Low, // low
this.chartDataCandleStick[i].Close // close
]);
this.volumeDataArray.push([
this.chartDataCandleStick[i].Date, // the date
this.chartDataCandleStick[i].Volume // the volume
]);
}
for (i; i < indicatorUpperDataLength; i += 1) {
this.indicatorUpperDataArray.push([
this.chartDataIndicatorUpper[i].Date, // the date
this.chartDataIndicatorUpper[i].Indicator // the upper indicator
]);
}
for (i; i < indicatorLowerDataLength; i += 1) {
this.indicatorLowerDataArray.push([
this.chartDataIndicatorLower[i].Date, // the date
this.chartDataIndicatorLower[i].Indicator // the lower indicator
]);
}
// Add a null value for the end date
if (candleStickDataLength > 0) {
var endDateChartCandleStick = this.chartDataCandleStick[candleStickDataLength - 1].Date;
this.chartDataCandleStick = [].concat(this.chartDataCandleStick, [
[endDateChartCandleStick, null, null, null, null]
]);
}
if (indicatorUpperDataLength > 0) {
var endDateChartIndicatorUpper = this.chartDataIndicatorUpper[indicatorUpperDataLength - 1].Date;
this.chartDataIndicatorUpper = [].concat(this.chartDataIndicatorUpper, [
[endDateChartIndicatorUpper, null, null, null, null]
]);
}
if (indicatorLowerDataLength > 0) {
var endDateChartIndicatorLower = this.chartDataIndicatorLower[indicatorLowerDataLength - 1].Date;
this.chartDataIndicatorLower = [].concat(this.chartDataIndicatorLower, [
[endDateChartIndicatorLower, null, null, null, null]
]);
}
if (!this.chart) {
this.chart = 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.chartDataCandleStick
}
},
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
}
},
{
type: 'flags',
name: 'Flags on series',
data: [
{
x: 946980000000,
title: 'Buy',
text: 'Some event with a description'
},
{
x: 946980060000,
title: 'Sell',
text: 'Some event with a description'
},
{
x: 946980060001,
title: 'Short',
text: 'Some event with a description'
},
{
x: 946980120000,
title: 'Buy',
text: 'Some event with a description'
},
{
x: 946980120001,
title: 'Buy',
text: 'Some event with a description'
},
{
x: 946980180000,
title: 'Sell',
text: 'Some event with a description'
},
{
x: 946980180001,
title: 'Short',
text: 'Some event with a description'
},
{
x: 946980240000,
title: 'Buy',
text: 'Some event with a description'
},
{
x: 946980240001,
title: 'Buy',
text: 'Some event with a description'
}
],
onSeries: 'dataseries',
shape: 'squarepin'
}
]
};
}
}
回答1:
I come from freelancer and I have looked at your code and if I was in your in your shoes I would try a few things first, the first of which is to hard bind the function like so:
afterSetExtremes: this.afterSetExtremes.bind(this)
or add a reference to it like so
const afterSetExtremes = this.afterSetExtremes;
and then reference it in your config object.
来源:https://stackoverflow.com/questions/59806505/angular-cli-this-resolves-to-a-child-component-instead-of-the-main-component