I'm trying to have an observable that is based on a Subject, so that it gets updated every time the SUbject emits.
For some reason, when trying to fetch the value of the observable, first value is always null, and rest contain values. I shall expect to retrieve the latest emitted value of the observable. I've tried with all kind of SUbjects. What is what I'm missing?
...
activeBookings$: Subject<Booking[]> = new BehaviorSubject<Booking[]>(null);
activeBooking$: Observable<Booking> = this.activeBookings$.pipe(
filter((bookings) => bookings?.length > 0),
mergeMap((bookings) => this.getBookingById(bookings?.[0]?.id)),
share()
);
i = 0;
constructor(
public http: HttpClient,
public store: Store,
public asyncPipe: AsyncPipe,
public bookingStoreService: BookingStoreService
) {
this.getBookings().subscribe((bookings) => {
this.bookings$.next(bookings);
});
this.getActiveBookings().subscribe((bookings) => {
this.activeBookings$.next(bookings);
});
this.getPreviousBookings().subscribe((bookings) => {
this.previousBookings$.next(bookings);
});
}
...
Here is where I try to obtain the latest value:
...
const booking: Booking = this.asyncPipe.transform(
this.bookingService.activeBooking$
);
booking.status = status; //error: booking is null
...
CodePudding user response:
You are using a BehaviorSubject here with an initial value of null:
activeBookings$: Subject<Booking[]> = new BehaviorSubject<Booking[]>(null);
You could initialise it with an empty array instead for exemple:
activeBookings$: Subject<Booking[]> = new BehaviorSubject<Booking[]>([]);
It would be more consistent type wise else your real type is:
activeBookings$: Subject<Booking[] | null> = new BehaviorSubject<Booking[] | null>(null);
Why are you getting null ? A BehaviorSubject needs to be initialised with a value and that is probably why the first value you get is null. A plain Subject doesn't need to contain an initial value and you would probably not get null
activeBookings$: Subject<Booking[]> = new Subject<Booking[]>()
A cleaner way to obtain the latest value without subscribing in your other service would be to leverage the features of the BehaviorSubject and the fact that calling activeBooking$.value makes you retrieve the latest value of the BehaviorSubject. Transform your activeBooking$ field so that it is a BehaviorSubject and when subscribing to the result of getActiveBookings(), you could do the computing that is currently in the pipe of the activeBooking$ definition there and call next on activeBooking$ with the result and expose a getter for your other service:
get activeBooking(): Booking {
return this.activeBooking$.value
}