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

时间:2017-10-11 22:09:55

标签: angular typescript firebase firebase-realtime-database observable

我从一个返回一个Payment对象数组的服务中有一个observable,一旦我订阅了我的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循环有关,因为数组仍然是空的,我认为一旦web套接字连接后续更新得到足够快的推送?

1 个答案:

答案 0 :(得分:0)

getPaymentsByDateRange()方法断开连接。您在填充之前返回paymentsArray。

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
     });