我试图显示从服务器(使用Angular 6,Rxjs和Chartjs)检索到的数据,并使用该数据呈现图表。 如果我使用本地模拟数据,那么一切都会很好地呈现。但是,如果我使用从服务器获取数据,则无法提供渲染图形所需的数据,因此这些图表将显示为空白图表。
摘要: 组件进行服务调用,并使用该服务调用的响应准备要传递给子组件的对象。但是,到响应准备就绪时,该对象已经发送了,而没有必要的信息。
服务代码段:
apply
在client-info.component.ts 中(用于进行服务调用并准备并将对象传递给子组件的组件)
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', []))
);
}
我正在使用ngOnChanges(在子组件中)寻找更改,但是在“ clientAccounts”数组填充响应后,在子组件中不更新图表数据。
@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
};
}
您能指出我应该如何继续对此进行研究吗?
很长的问题,很抱歉,谢谢!
编辑:根据要求,模板位于以下
父母(客户信息):
@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>
答案 0 :(得分:2)
我看到,您没有将数据直接分配给this.barChart
,而是将其分配为this.barChart.data
,这意味着您正在直接修改属性,而该属性可能不会调用{{1} }子组件。这是由于您在评论中给出的解释。
我读到这可能是因为角度变化检测检查了 通过查看对象引用来实现差异
并且不知道对象的属性何时更改
绑定到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();
})
设置为0的原因
答案 1 :(得分:1)
答案 2 :(得分:1)
public function send_mail() { $this->load->library('email'); $name = $this->input->post("name"); $email = $this->input->post("email"); $config['protocol'] = 'smtp'; $config['smtp_host'] = 'mail.*******.com'; $config['smtp_port'] = '465'; $config['smtp_timeout'] = '7'; $config['smtp_user'] = 'info@*******.com'; $config['smtp_pass'] = '*********'; $config['charset'] = 'utf-8'; $config['newline'] = '\r\n'; $config['mailtype'] = 'text'; // or html $config['validation'] = TRUE; $this->email->initialize($config); $this->email->from('info@*******.com', 'Hima'); $this->email->to($email); $this->email->subject('email verification'); $this->email->message('Verification Code'); $send = $this->email->send(); if ($send) { $this->session->set_flashdata('msg','success'); } else { echo $error = $this->email->print_debugger(); } }
ngOnChanges的自变量值为每个ngOnChanges(changes: SimpleChanges) {
if (changes['accountBalanceStatus'] || changes['chart']) {
this.renderChart();
}
}
的{{3}}类型
道具:
Input()
您应按class SimpleChange {
constructor(previousValue: any, currentValue: any, firstChange: boolean)
previousValue: any
currentValue: any
firstChange: boolean
isFirstChange(): boolean
}
,previousValue
检查数据。
像这样:
currentValue
答案 3 :(得分:0)
您需要与父级的子级组件交互,以使用输入绑定。
引用:
https://angular.io/guide/component-interaction#pass-data-from-parent-to-child-with-input-binding
答案 4 :(得分:0)
我的问题已解决,我希望与大家分享解决方案,以防将来有人需要。正如阿米特·奇加达尼(Amit Chigadani)建议的那样(在评论中),在我的订阅块中调用我的图表更新功能是有效的。
getAccountsOfClientId(clientID: string): void {
this.clientAccountService.getAccountsOfClientId(this.client.id)
.subscribe(accounts => {
this.clientAccounts = accounts;
this.updateChart();
this.updateBarChart();
});
}