从可观察到的返回数据的角度 forEach 循环(Firebase 驱动)

Posted

技术标签:

【中文标题】从可观察到的返回数据的角度 forEach 循环(Firebase 驱动)【英文标题】:Angular forEach Loop on returned data from observable (Firebase driven) 【发布时间】:2018-03-23 17:24:41 【问题描述】:

我有一个来自服务的 observable,它返回一个 Payment 对象数组,一旦我订阅了我的 observable,我就会执行一个循环来添加数组中每个对象的数量。我在第一次加载时遇到的问题是循环没有被执行,因为我认为是因为数据尚未到达,但是,如果我在 observable 的主题上触发 .next 它工作正常。

我的组件的功能是这样的:

paymentsSource = new Subject;
payments$ = this.paymentsSource.asObservable();
paymetsData:Payment[] = new Array();
totalPaymentsAmoutn:number = 0;

ngOnInit() 
  this.payments$
    .subscribe(
     (dates:startDate:number, endDate:number) => 
     //Here I need to performe some UTC and Locale conversion to dates thet are being passed on          
      ;
      //Here I subscribe to my service          
      this.paymentService.getPaymentsByDateRange(dates.startDate, dates.endDate)
       .subscribe(
         payments => 
          this.totalPaymentsAmoutn = 0;
          this.paymetsData = payments;
          this.paymetsData.forEach( payment => 
            this.totalPaymentsAmoutn += payment.amount;
           )
          );      
       );


//this.paymentsStartDate is declear some where else but it does exist previous to this point
this.paymentsSource.next(startDate:this.paymentsStartDate, endDate:this.paymentsStartDate);



//This function I can triger manualy on the view
onPaymentDateRangeChanged($event)
  this.paymentsSource.next(startDate:$event.startDate, endDate:$event.endDate);

我的服务功能如下所示:

  getPaymentsByDateRange(startDate:number, endDate:number):Observable<Payment[]>
    let paymentsArray:Payment[] = [];
    this.af.list('/bookings')
      .subscribe(
        (bookings) => 
          for(let booking of bookings)
            if(booking.payments)
              for(let payment of booking.payments)
                //condition for date range
                if(startDate <= payment.date && payment.date <= endDate)
                  payment.booking_key = booking.$key; 
                  paymentsArray.push(payment);
                
              
            
          
          //Sorting payments cronologicaly
          paymentsArray.sort(function(paymentA, paymentB)
            return paymentA.date - paymentB.date
          );
        
      );
    return Observable.of(paymentsArray);
  

当页面加载时,我确实取回了数组并填充了视图,但 this.totalPaymentsAmoutn 的值仍然为 0,如果我手动触发该函数,它会返回数组并完美更新 this.totalPaymentsAmoutn。

我对 Observables 有点陌生,我认为一旦我订阅它,如果发出新数据它应该运行脚本并更新数据,我不明白为什么第一次加载不起作用。我真的认为这与无法执行 forEach 循环有关,因为数组仍然是空的,我认为一旦网络套接字连接,后续更新就会足够快地推送?

【问题讨论】:

【参考方案1】:

您的 getPaymentsByDateRange() 方法中存在断开连接。您在填充之前返回支付数组。

getPaymentsByDateRange(startDate: number, endDate: number): Observable<Payment[]>
    let paymentsArray: Payment[] = [];
    this.af.list('/bookings')
        .subscribe(...); // asynchronous
    // since this.af.list.subscribe is asynchronous, this returns before that call is finished.
    return Observable.of(paymentsArray);

您应该改为返回 af.list observable 并仅在组件中订阅。如果需要在组件使用前对数据进行预处理,可以使用 rxjs .map 操作符

import 'rxjs/add/operator/map'; // import map operator

getPaymentsByDateRange(startDate: number, endDate: number): Observable<Payment[]>
    let paymentsArray: Payment[] = []; // you may want to move this inside the map. If you don't you may get duplicates everytime firebase emits the bookings
    return this.af.list('/bookings')
        .map(bookings => 
            for(let booking of bookings)
                if(booking.payments)
                    for(let payment of booking.payments)
                        //condition for date range
                        if(startDate <= payment.date && payment.date <= endDate)
                            payment.booking_key = booking.$key; 
                            paymentsArray.push(payment);
                        
                    
                
            
            //Sorting payments cronologicaly
            paymentsArray.sort(function(paymentA, paymentB)
                return paymentA.date - paymentB.date
            );
            return paymentsArray;
        );

这确保当您订阅此方法时,onNext 回调只会在af.list observable 发出时触发。

 this.paymentService.getPaymentsByDateRange(dates.startDate, dates.endDate)
     .subscribe(payments => 
         // fires when af.list observable emits
     );

【讨论】:

非常感谢,这真的很容易清除它,现在我明白它为什么会这样了。一件小事我仍然需要在 .map 之后执行一个 for 循环来遍历 firebase 返回的列表中的每个项目。 for(let booking of bookings) .... @Xazzo 很好,我忘了将其添加到我的答案中。更新

以上是关于从可观察到的返回数据的角度 forEach 循环(Firebase 驱动)的主要内容,如果未能解决你的问题,请参考以下文章

Angular 4 - 从可观察到的将新项目推送到数组

我如何从可观察对象创建对象,该对象返回对象数组

使用异步管道从可观察对象中读取对象字段

无法从可观察对象中提取数据

当其他可观察对象为真时,从可观察对象中获取项目

角度形式控制最后可观察到的变化