[英]How to pass async data to child components in an object (Angular6)
我正在嘗試顯示從服務器檢索的數據(使用Angular 6,Rxjs和Chartjs),並使用數據呈現圖表。 如果我使用本地模擬數據,一切都很好。 但是,如果我使用從服務器獲取數據,則無法呈現圖形所需的數據,因此圖表將呈現為空白圖表。
簡介:組件進行服務調用,並使用服務調用的響應准備對象以傳遞給子組件。 但是,在響應准備就緒時,已經發送了沒有必要信息的對象。
服務代碼段 :
getAccountsOfClientId(clientID: string): Observable<Account[]> {
return this.http.get<Account[]>(`${this.BASE_URL}/accounts?client=${clientID}`)
.pipe(
tap(accounts => console.log('fetched client\'s accounts')),
catchError(this.handleError('getAccountsOfClientId', []))
);
}
在client-info.component.ts (進行服務調用的組件,並准備並將對象傳遞給子組件)
@Input() client; // received from another component, data is filled
constructor(private clientAccountService: ClientAccountService) { }
ngOnInit() {
this.getAccountsOfClientId(this.client.id);
}
ngAfterViewInit() {
this.updateChart(); // render for pie chart
this.updateBarChart(); // render for bar chart
}
getAccountsOfClientId(clientID: string): void {
this.clientAccountService.getAccountsOfClientId(this.client.id)
.subscribe(accounts => this.clientAccounts = accounts);
}
updateBarChart(updatedOption?: any): void {
/* unrelated operations above ... */
// Create new base bar chart object
this.barChart = {};
this.barChart.type = 'bar';
this.setBarChartData();
this.setBarChartOptions('Account', 'Balance');
}
setBarChartData(): void {
// field declarations..
console.log('clientAccounts has length: ' + this.clientAccounts.length); // prints 0
this.clientAccounts.map((account, index) => {
// do stuff
});
dataset = {
label: 'Balance',
data: data,
...
};
datasets.push(dataset);
// since clientAccounts was empty at the time this function ran, the "dataset" object doesn't contain
// the necessary information for the chart to render
this.barChart.data = {
labels: labels,
datasets: datasets
};
}
我在尋找使用ngOnChanges(在子組件)的變化,但是圖表數據是不是在子組件更新“clientAccounts”陣列充滿響應之后。
@Input() chart: Chart;
@Input() canvasID: string;
@Input() accountBalanceStatus: string;
ngOnChanges(changes: SimpleChanges) {
if (changes['accountBalanceStatus'] || changes['chart']) {
this.renderChart();
}
}
renderChart(): void {
const element = this.el.nativeElement.querySelector(`#${this.canvasID}`);
if (element) {
const context = element.getContext('2d');
if (this.activeChart !== null) {
this.activeChart.destroy();
}
this.activeChart = new Chart(context, {
type: this.chart.type,
data: this.chart.data,
options: this.chart.options
});
} else {
console.log('*** Not rendering bar chart yet ***');
}
}
你能指點我應該如何繼續我的研究嗎?
抱歉,這個問題很長,謝謝!
編輯 :根據要求,模板如下
父(客戶信息) :
<div class='client-info-container'>
<div class='info-container'>
<li>Date of Birth: {{ client.birthday | date: 'dd/MM/yyyy' }}</li>
<li>Name: {{ client.name }}</li>
<li>First Name: {{ client.firstname }}</li>
</div>
<div class='more-button'>
<button (click)='openModal()'>More</button>
</div>
<div class='chart-container'>
<div *ngIf='pieChart && client'>
<app-balance-pie-chart
[chart]='pieChart'
[canvasID]='accountBalancePieChartCanvasID'
(updateChart)='handlePieChartOnClick($event)'>
</app-balance-pie-chart>
</div>
<div class='bar-chart-container'>
<div class='checkbox-container'>
<div *ngFor='let option of cardTypeCheckboxOptions' class='checkbox-item'>
<input
type='checkbox'
name='cardTypeCheckboxOptions'
value='{{option.value}}'
[checked]='option.checked'
[(ngModel)]='option.checked'
(change)="updateCardTypeCheckboxSelection(option, $event)"/>
<p>{{ option.name }} {{ option.checked }}</p>
</div>
</div>
<div *ngIf='barChart && client'>
<!-- *ngIf='client.accounts.length === 0' -->
<div class="warning-text">This client does not have any accounts.</div>
<!-- *ngIf='client.accounts.length > 0' -->
<div>
<app-balance-account-bar-chart
[chart]='barChart'
[canvasID]='accountBarChartCanvasID'
[accountBalanceStatus]='accountBalanceStatus'>
</app-balance-account-bar-chart>
</div>
</div>
</div>
</div>
</div>
圖表:
<div class='bar-chart-canvas-container' *ngIf='chart'>
<canvas id='{{canvasID}}' #{{canvasID}}></canvas>
</div>
我看到了,你沒有直接將數據分配給this.barChart
而是將它指定為this.barChart.data
,這意味着你要直接修改屬性,這可能不會調用子組件的ngOnChanges
。 這是由於您在評論中給出的解釋。
我讀到這可能是因為角度變化檢測通過查看對象引用來檢查差異
並且它不會知道對象的屬性何時被改變
綁定到@Input()
屬性的變量是this.barChart
而不是this.barChart.data
。
代替
this.barChart.data = {
labels: labels,
datasets: datasets
};
你試試這個
this.barChart = {
data : {
labels: labels,
datasets: datasets
}};
在這里你直接修改this.barChart
應該觸發ngOnChanges()
。
編輯:
你應該調用this.updateChart();
里面的subscribe
塊
this.clientAccountService.getAccountsOfClientId(this.client.id)
.subscribe((accounts) => {
this.clientAccounts = accounts;
this.updateChart();
})
這就是為什么你也將this.clientAccounts.length
設為0
ngOnChanges(changes: SimpleChanges) { if (changes['accountBalanceStatus'] || changes['chart']) { this.renderChart(); } }
ngOnChanges的參數值是每個Input()
prop的SimpleChanges的類型:
class SimpleChange {
constructor(previousValue: any, currentValue: any, firstChange: boolean)
previousValue: any
currentValue: any
firstChange: boolean
isFirstChange(): boolean
}
您應該通過previousValue
, currentValue
檢查數據。 就像是:
if(changes.accountBalanceStatus.previousValue != changes.accountBalanceStatus.currentValue
|| changes.chart.previousValue != changes.chart.currentValue){
this.renderChart();
}
您需要與來自父級的子組件進行交互,以便使用輸入綁定。
參考:
https://angular.io/guide/component-interaction#pass-data-from-parent-to-child-with-input-binding
我的問題已經解決,我想分享解決方案以防將來有人需要它。 正如Amit Chigadani建議的那樣(在評論中),在訂閱塊中調用我的圖表更新功能。
getAccountsOfClientId(clientID: string): void {
this.clientAccountService.getAccountsOfClientId(this.client.id)
.subscribe(accounts => {
this.clientAccounts = accounts;
this.updateChart();
this.updateBarChart();
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.