簡體   English   中英

如何將異步數據傳遞給對象中的子組件(Angular6)

[英]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

您的組件需要在呈現之前獲取數據。 您可以使用resolve ,這是Angular提供的內置功能,用於處理您所描述的用例。

還看這里 可能是教程表單中的有用資源。

 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
}

您應該通過previousValuecurrentValue檢查數據。 就像是:

if(changes.accountBalanceStatus.previousValue != changes.accountBalanceStatus.currentValue 
   || changes.chart.previousValue  != changes.chart.currentValue){
 this.renderChart();
}

StackBlitz演示

您需要與來自父級的子組件進行交互,以便使用輸入綁定。

參考:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM