[英]Angular forEach Loop on returned data from observable (Firebase driven)
I have an observable from a service that returns an array of Payment objects, once I subscribe to my observable I perform a loop to add the amounts of each of the objects in the array. 我有一个可观察到的服务,该服务返回了一系列Payment对象,一旦我订阅了我的可观察对象,便执行循环以添加该数组中每个对象的数量。 the problem I'm having that on the first load the loop is not being executed for what I assume is because the data has not yet arrived, however, if I trigger .next on the subject of the observable it workes fine.
我遇到的问题是,在第一次加载时,由于我认为是因为数据尚未到达,所以尚未执行循环,但是,如果我在可观察的主题上触发.next,它可以正常工作。
The function of my component is like so: 我组件的功能如下:
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});
}
My Service function looks like this: 我的服务功能如下所示:
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);
}
When the page loads I do get the array back and the view gets populated but the value for this.totalPaymentsAmoutn remains 0, if I trigger the function manually it returns the array and updates the this.totalPaymentsAmoutn perfectly. 当页面加载时,我确实获取了数组并填充了视图,但是this.totalPaymentsAmoutn的值保持为0,如果我手动触发该函数,它将返回数组并完美地更新this.totalPaymentsAmoutn。
I am a bit new with Observables and I thought that once I subscribe to it if new data gets emitted It should run the script and update the data, I don't understand why on the first load is not working. 我对Observables有点陌生,我认为一旦发出新数据,我就订阅它,它应该运行脚本并更新数据,但我不明白为什么第一次加载无法正常工作。 I really think it has to do with not being able to perform the forEach loop since the array is still empty and I think that once the web sockets get connected consequent updates get push fast enough?
我真的认为这与无法执行forEach循环有关,因为该数组仍然为空,并且我认为一旦Web套接字建立连接,后续更新就会被足够快地推送吗?
There is a disconnect in your getPaymentsByDateRange()
method. 您的
getPaymentsByDateRange()
方法中存在断开连接。 You are returning the paymentsArray before it is populated. 您将在填充之前返回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);
}
You should instead return the af.list
observable and subscribe only in the component. 相反,您应该返回可观察到的
af.list
并仅在组件中进行订阅。 If you need to preprocess the data before the component uses it, you can use the rxjs .map operator 如果需要在组件使用数据之前对其进行预处理,则可以使用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;
});
}
This ensures that when you subscribe to this method, the onNext callback will only fire once the af.list
observable emits. 这样可以确保在您订阅此方法时,仅在
af.list
observable发出后才触发onNext回调。
this.paymentService.getPaymentsByDateRange(dates.startDate, dates.endDate)
.subscribe(payments => {
// fires when af.list observable emits
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.