I am writing a service that I intend will store local copies of Place objects and fetch them from a back end only when they are not stored locally. However, I am having trouble implementing this functionality. I could set up my page to call fetchPlace() if the value from place() is undefined, but I intend on keeping fetchPlace() private so that I may later implement a system for checking if a request was made recently so that the server isn't flooded with requests if the user rapidly switches pages.
places.service.ts
export class PlacesService {
private _places = new BehaviorSubject<Place[]>([]);
get places() {
return this._places.asObservable();
}
constructor(private _http: HttpClient) {}
place(placeId: number): Observable<Place> {
return this._places.pipe(
take(1),
map((places: Place[]) => {
console.log(places);
let place = places.find((place: Place) => place.id === placeId);
if (place === undefined) {
console.log('Time to send a request!');
this.fetchPlace(placeId).subscribe(
(fetchedPlace: Place) => {
console.log('We got one!');
place = fetchedPlace;
console.log(place);
},
(error) => {
console.error('Looks like a 404.');
},
);
}
console.log('Okay, returning place now!');
return place;
}),
);
}
private fetchPlace(placeId: number): Observable<Place> {
return this._http
.get<Place.ResponseBody>(`http://localhost:8000/v1/places/${placeId}/`)
.pipe(map((response: Place.ResponseBody) => Place.create(response)));
}
}
The problem with the code above is that when the variable place is undefined, the subscription to fetchPlace() gets called asynchronously, so place is returned before the value of place is overwritten by fetchedPlace. I would like some way of returning an observable containing place from the place() function.
For completion's sake, here is how the code above is called, and the console output:
place-detail.page.ts
ngOnInit() {
this._route.paramMap.subscribe((paramMap: ParamMap) => {
if (!paramMap.has('placeId')) {
this._navCtrl.navigateBack('/places/discover');
return;
}
const placeId = +paramMap.get('placeId');
this._placesSub = this._placesSrv.place(placeId).subscribe(
(place: Place) => {
if (place === undefined) {
console.log('Got here.');
} else {
this._isBookable = place.user !== this._authSrv.user;
this._place = place;
}
},
(error) => {
console.error(error);
}
);
});
}
Console
Angular is running in development mode. Call enableProdMode() to enable production mode. core.js:26833
Native: tried calling StatusBar.styleDefault, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator common.js:284
Native: tried calling SplashScreen.hide, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator common.js:284
[WDS] Live Reloading enabled. client:52
Array []
places.service.ts:81:16
Time to send a request! places.service.ts:85:18
Okay, returning place now! places.service.ts:98:16
Got here. place-detail.page.ts:75:20
We got one! places.service.ts:88:22
Object { _id: 1, _user: 2, _title: "Manhattan Mansion", _description: "In the heart of New York City.", _imgUrl: "https://www.idesignarch.com/wp-content/uploads/New-York-Fifth-Avenue-Mansion_1.jpg", _price: "149.99", _availableFrom: Date Fri Dec 31 2021 18:00:00 GMT-0600 (Central Standard Time), _availableTo: Date Sat Dec 30 2023 18:00:00 GMT-0600 (Central Standard Time) }
places.service.ts:90:22