首页 > 解决方案 > Angular/Firebase 应用程序不断显示上一页的数据

问题描述

我有一个带有主页的 Angular 应用程序,其中显示了“事务”Firebase 集合中的 4 个最新行(按日期排序,降序)。然后是一个单独的交易页面,我在其中显示了该集合中的前 10 行(按金额排序,降序)。但是,当我从主页开始然后转到交易页面时,在我的条形图中应该按金额显示前 10 笔交易,我仍然可以看到主页上最近的 4 笔交易。

演示链接: https ://tickrs-app.web.app/

重现步骤:

  1. 打开演示应用
  2. 在最底部的主页上,您会看到“最近的交易”
  3. 打开菜单并导航到“交易”页面
  4. 条形图看起来有点奇怪,似乎数据仍然包含来自主页的 4 个最近交易
  5. 导航到不同的页面(不是主页),然后返回“交易”页面,条形图现在应该看起来正常

这是我的home.page.ts代码:

  // Function to load the 4 most recent transactions to show on the home page
  async loadData() {
    // Order by date, descending
    const orderParamsDateDesc = {
      field: 'date',
      order: 'desc'
    }
    
    // Call our service to load the data, given the ordering details, and limit the number of rows to 4
    await this._FirebaseService.readSortLimit('transactions', orderParamsDateDesc, 4).then(result => this.transactionRows = result);
  }

  async ngOnInit() {
    // Only try to load the data if the user is authenticated again
    this.afAuth.onAuthStateChanged(async () => {
      await this.loadData();
    })
  }

这是transaction.page.ts的相同代码:

  // Function to load the top 10 transactions, ordered by amount (descending)
  async getRows() {
    // Initialize the arrays
    this.barChartDataEur = [];
    this.barChartLabelsEur = [];
    let rows: any = [];

    // Order by amount, descending
    let orderParams = {
      field: 'amount',
      order: 'desc'
    }

    // Call our service to load the data given the ordering details, and limit the number of rows to 10
    await this._FirebaseService.readSortLimit("transactions", orderParams, 10).then(result => rows = result);

    // Loop over the resulting rows and load the stock tickers and amount separately in the arrays which will be used for the bar chart
    await rows.forEach(row => {
      this.barChartLabelsEur.push(row.ticker.slice(0, 8));
      this.barChartDataEur.push(row.amount);
    });

    // Set the loaded flag to true
    this.loaded = true;
  }

  ngOnInit() {
    // Only execute this part if user is authenticated
    this.afAuth.onAuthStateChanged(async () => {
      this.getRows();
    })
  }

这是用于呈现条形图的transaction.page.html的一部分:

  <div class="chart-canvas">
    <canvas baseChart *ngIf="loaded"  // Only if data is loaded
            [data]="barChartDataEur"
            [labels]="barChartLabelsEur"
            [chartType]="barChartType"
            [options]="barChartOptions"
            [colors]="barChartColors"
            [legend]="barChartLegend"
            [plugins]="barChartPlugins">
    </canvas>
  </div>

这是我的firebase.service.ts和两个页面都使用的 readSortLimit 函数:

  // Input: name of the Firebase collection, the ordering details and the number of rows to return
  readSortLimit(collection, orderDetails, limitNumber) {
    return new Promise((resolve, reject) => {
      let result = [];
      this.firestore
        .collection(collection, ref => ref
          .orderBy(orderDetails.field, orderDetails.order)
          .limit(limitNumber)
        )
        .snapshotChanges()
        .subscribe(item => {
          Array.from(item).forEach(row => {
            result.push(row.payload.doc.data());
          });
          resolve(result);
        });
    });
  }

标签: javascriptangularfirebasegoogle-cloud-firestoreangularfire

解决方案


snapshotChanges可能首先处理并从缓存中返回数据作为快速结果。您的函数readSortLimit返回一个承诺,并且承诺通过缓存中的数据解决。Nextresolve被忽略。

您需要修改函数readSortLimit以返回Observable

  readSortLimit(collection, orderDetails, limitNumber) {
    return this.firestore
        .collection(collection, ref => ref
          .orderBy(orderDetails.field, orderDetails.order)
          .limit(limitNumber)
        )
        .snapshotChanges()
        .subscribe(items => {
          Array.from(items).map(row => row.payload.doc.data()));
        });
  }

然后修改getRows

  async getRows() {
    // Order by amount, descending
    let orderParams = {
      field: 'amount',
      order: 'desc'
    }

    // Call our service to load the data given the ordering details, and limit the number of rows to 10
    this._FirebaseService.readSortLimit("transactions", orderParams, 10)
           .subscribe(rows => {
             // Initialize the arrays
             this.barChartDataEur = [];
             this.barChartLabelsEur = [];

             // Loop over the resulting rows and load the stock tickers and amount separately in the arrays which will be used for the bar chart
             rows.forEach(row => {
               this.barChartLabelsEur.push(row.ticker.slice(0, 8));
               this.barChartDataEur.push(row.amount);
             }); 
             
             // Set the loaded flag to true
             this.loaded = true;            
           });
  }

**确保getRows最多调用一次。否则,您将多次订阅同一事件。


推荐阅读