我在角度4应用程序中实现了高图。我的高图似乎加载了两次相同的系列。我使用@Input()设置stressTestResults声明来调用addseries方法。我可以看到断点在那里击中两次并调用addseries两次。我不知道如何防止这被调用两次。如果我将addseries移动到ngOnInit,它然后在加载图表时没有得到值,并且在刷新页面时,我可以看到值通过。这次它正确显示了一个系列。如果Init是正确的位置,则存在变更检测或检索数据滞后的问题。有人能告诉我哪里出错了吗
import { Component, OnInit, Input,ViewChild } from '@angular/core';
import { StressTestAnalysis } from '../../../../api/dtos';
import { ReactiveComponent } from '@wtw/toolkit/src/utils/base.component';
import { SplineChartComponent } from '../../../../shared/Highcharts/spline/spline-chart.component';
export interface ChartSeries {
data: number[][];
name: string;
color: string;
}
@Component({
selector: 'app-stress-test-analysis',
templateUrl: './stress-test-analysis.component.html'
})
export class StressTestAnalysisComponent extends ReactiveComponent implements OnInit {
isExpanded = false;
showTable = true;
private results: Array<StressTestAnalysis> = [];
@ViewChild(SplineChartComponent) public stressSplineChart: SplineChartComponent;
//@Input() results: Array<StressTestAnalysis> = [];
@Input() set stressTestResults(value: Array<StressTestAnalysis>) {
this.results = value;
this.addSeries();
}
public chartSeries: Array<ChartSeries> = [];
seriesName: string;
strategyName: string = '';
constructor(
) { super(); }
ngOnInit() {
// this.addSeries();
}
private addSeries() {
if (this.results === null) {
return;
}
this.results.forEach(element => {
if (element !== null) {
this.chartSeries.push({ data: element.graphData, name: element.seriesName, color: element.color });
// if (this.stressSplineChart) this.stressSplineChart.redraw();
}
});
}
}
父组件html
你可以在这里看到我已经将stressTestResults初始化为子组件的stressTestResults属性
<div class="container-fluid mt-3 mb-3 test-feasibility--details">
<app-assumptions-summary></app-assumptions-summary>
</div>
<form #pageForm="ngForm">
<div class="container-fluid base_strategy p-0 m-0">
<div class="tb-container col-md-12 p-0 m-0 scroll-auto">
<app-strategies [strategies]="run.strategies" [linesOfBusinessInput]="run.linesOfBusinessInput" [redraw]="forceRedraw" (applyChange)="applyChange($event)" (save)="save()"></app-strategies>
<div class="col-12 test_feasibility--accordion">
<!-- Accordion -->
<div id="accordion" role="tablist">
<app-net-present-value-analysis [npvResults]="npvResults"></app-net-present-value-analysis>
<app-economic-value-analysis [evResults]="evResults"></app-economic-value-analysis>
<app-stress-test-analysis [stressTestResults]="stressTestResults"></app-stress-test-analysis>
<app-ending-surplus-analysis [results]="endingSurplusResults"></app-ending-surplus-analysis>
</div>
<!-- Accordion End -->
</div>
</div>
</div>
</form>
图表组件
import { Component, Input, OnChanges } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'splinechart',
template: '<chart [options]="options" (load)="getInstance($event.context)"></chart>',
styles: [`
chart {
display: block;
width: 100% !important;
padding:0;
}`]
})
export class SplineChartComponent implements OnChanges {
public options: any;
chart: any;
@Input() public series: any;
@Input() public yaxisdata: any;
@Input() public selectedRating: string = '';
constructor(private _translate: TranslateService) {
this.options = {
credits: {
enabled: false
},
chart: {
type: 'spline'
},
title: {
text: ''
},
subtitle: {
text: ''
},
legend: {
layout: 'horizontal',
margin: 25,
itemMarginTop: 0,
symbolRadius: 0,
symbolHeight: 20,
symbolWidth: 20,
useHTML: true,
title: {
text: this._translate.instant('CAPTIVES.RESULTS.COMMON.GRAPH_LEGEND_TITLE'),
margin: 50,
style: {
fontStyle: 'italic',
fontWeight: 'normal'
}
},
align: 'right',
verticalAlign: 'bottom',
},
xAxis: {
title: {
text: this._translate.instant('CAPTIVES.RESULTS.STA.GRAPH_XAXIS')
}
},
yAxis: {
title: {
text: this._translate.instant('CAPTIVES.RESULTS.STA.GRAPH_YAXIS')
}
},
tooltip: {
},
plotOptions: {
series: {
cursor: 'pointer',
events: {
legendItemClick: function() {
const elements = document.querySelectorAll('.highcharts-legend-item path');
for (let i = 0; i < elements.length; i++) {
elements[i].setAttribute('stroke-width', '20');
elements[i].setAttribute('stroke-height', '20');
}
this.chart.redraw();
}
},
allowPointSelect: true,
},
spline: {
lineWidth: 2,
states: {
hover: {
lineWidth: 3
}
},
marker: {
enabled: true,
symbol: 'circle'
},
}
},
series: [
{
showInLegend: false
}
]
};
}
getInstance(chartInstance): void {
this.chart = chartInstance;
this.redraw();
}
ngOnChanges(data: any) {
if (!data.series.currentValue || !this.chart) return;
var seriesLength = this.chart.series.length;
for(var i = seriesLength -1; i > -1; i--) {
this.chart.series[i].remove();
}
data.series.currentValue.map(s => {
this.chart.addSeries(s);
});
this.chart.reflow();
}
public redraw() {
if (!this.chart) return;
// var seriesLength = this.chart.series.length;
// for(var i = seriesLength -1; i > -1; i--) {
// this.chart.series[i].remove();
// }
this.series.map(s => {
if (s !== null)
this.chart.addSeries(s);
});
const elements = document.querySelectorAll('.highcharts-legend-item path');
for (let i = 0; i < elements.length; i++) {
elements[i].setAttribute('stroke-width', '20');
elements[i].setAttribute('stroke-height', '20');
}
this.chart.redraw();
}
}
父组件代码
import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { RunService, NavBarService } from '@wtw/platform/services';
import { Base } from '@wtw/toolkit';
import { NpvAnalysis, EvAnalysis } from '../../../shared/models/results';
import { Dto } from '@wtw/platform/api';
import { Strategy, StressTestAnalysis, CaptivesRun, EndingSurplus } from '../../../api/dtos';
import { RunModel } from '@wtw/platform/api/dtos';
@Component({
selector: 'app-results',
templateUrl: './results.component.html'
})
export class ResultsComponent extends Base.ReactiveComponent implements OnInit {
run: CaptivesRun;
npvResults: Array<NpvAnalysis> = [];
evResults: Array<EvAnalysis> = [];
stressTestResults: Array<StressTestAnalysis> = [];
endingSurplusResults: Array<EndingSurplus> = [];
forceRedraw: { value: number };
private _baseRun: Dto.RunModel;
constructor(
private _runService: RunService,
private _navBarService: NavBarService,
private _translate: TranslateService,
) {
super();
}
ngOnInit() {
this._subscriptions = [
this._runService.activeRun.subscribe((r: any) => {
this._processRun(r);
}),
this._runService.currencyConverted.subscribe(r => {
this._processRun(r);
this.save();
this.forceRedraw = { value: Math.random() * 10000 };
}),
this._navBarService.downloadReportEvent.subscribe(x => {
this.downloadReport();
})
];
}
downloadReport() {
console.log('download report');
}
applyChange(event: any) {
this.run.strategies.splice(event.index, 1, event.strategy);
this._baseRun.data = this.run;
this._runTrigger2(this._baseRun, event.index);
}
save() {
this._baseRun.data = this.run;
this._runService.persist(this._baseRun.runId, this.run, this._baseRun.currencyInfo).uiSignal('save').subscribe(x => {
this._processResults(this.run.strategies);
});
}
private _runTrigger2(r: Dto.RunModel, strategyIndex: number) {
this._runService.executeTrigger(r.runId, this.run, { number: 2, param: strategyIndex.toString() }, r.currencyInfo)
.uiSignal('trigger 2')
.subscribe(x => {
this.run = x.data;
this._processResults(x.data.strategies);
});
}
private _processRun(r: RunModel) {
this._baseRun = r;
this.run = r.data as CaptivesRun;
// Initialising the data
if (this.run.strategies) {
if (!this.run.strategies[0].results) {
this._runTrigger2(this._baseRun, 0);
} else {
this._processResults(this.run.strategies);
}
}
}
private _processResults(strategies: Array<Strategy>) {
this.npvResults = new Array();
this.evResults = new Array();
this.endingSurplusResults = new Array();
this.stressTestResults = new Array();
const strategyTranslation = this._translate.instant('CAPTIVES.RESULTS.COMMON.STRATEGY');
const getStrategyName = (strategy: Strategy, index: number) => {
let name = this._translate.instant('CAPTIVES.RESULTS.COMMON.BASE_STRATEGY');
if (index > 0) {
name = strategyTranslation + ' ' + index;
}
return name;
};
strategies.forEach((strategy, index) => {
const strategyName = getStrategyName(strategy, index);
const results = strategy.results;
this.npvResults.push(Object.assign(results.npvResult, { strategyName }));
this.evResults.push(Object.assign(results.evaResult, { strategyName }));
this.endingSurplusResults.push(Object.assign(results.endingSurplus));
this.stressTestResults.push(Object.assign(results.stressResult));
});
}
}
答案 0 :(得分:0)
我会尝试在@Input
中设置数组(并且只设置数据,不要调用addSeries()
)。然后实施onChanges
,并在ngOnChanges
中调用您的addSeries
方法。我认为正在发生的事情是@Input
被设置为ctor链的一部分,但是它在addSeries
中返回,因为数据尚未存在,并且它永远不会被再次调用。
类似于:
@Component({
selector: 'app-stress-test-analysis',
templateUrl: './stress-test-analysis.component.html'
})
export class StressTestAnalysisComponent extends ReactiveComponent implements OnChanges {
isExpanded = false;
showTable = true;
private results: Array<StressTestAnalysis> = [];
@ViewChild(SplineChartComponent) public stressSplineChart: SplineChartComponent;
@Input() results: Array<StressTestAnalysis>;
public chartSeries: Array<ChartSeries> = [];
seriesName: string;
strategyName: string = '';
constructor(
) { super(); }
ngOnChanges() {
this.addSeries();
}
private addSeries() {
if (!this.results) {
return;
}
this.results.forEach(element => {
if (element !== null) {
this.chartSeries.push({ data: element.graphData, name: element.seriesName, color: element.color });
// if (this.stressSplineChart) this.stressSplineChart.redraw();
}
});
}
}