angularrxjsrxjs-observablesrxjs-pipeable-operators

How to reuse the observable values in CRUD methods


In my get request, I need to send the set of headerParams, instead of calling the method to get the headerParams how can call and store as static value?

How to ensure other method to wait until the header details available?

Here is my service ts file:

    export class ForecastService extends EntityCollectionServiceBase<OpenWeatherResponse> implements OnInit {
    
      private url = 'https://api.openweathermap.org/data/2.5/forecast';
      httpUrlGenerator: any;
      headersParams: any; //always underfed
    
      constructor(serviceElementsFactory: EntityCollectionServiceElementsFactory, private http: HttpClient, private notificationService: NotificationsService) {
        super('Forecast', serviceElementsFactory);
      }
    
      ngOnInit() {
        this.headersParams = this.getCurrentLocation().subscribe(header => {
          this.headersParams = header; //not working. undefined
        });
      }
    
      override getAll(): Observable<OpenWeatherResponse[]> {
    
    //need to avoid it
        return this.getCurrentLocation().pipe(
          map(coords => {
            return new HttpParams()
              .set('lat', String(coords.latitude))
              .set('lon', String(coords.longitude))
              .set('units', 'metrics')
              .set('appid', '...........')
          }),
          switchMap(params => this.http.get<OpenWeatherResponse[]>(this.url, {params})),
          map((value: any) => value.list),
          mergeMap((value: OpenWeatherResponse[]) => of([...value])),
          filter((value, index) => index % 8 === 0),
          map(value => value)
        )
      }
    
      getForecast() {
//need to avoid it
        return this.getCurrentLocation()
          .pipe(
            map(coords => {
              return new HttpParams()
                .set('lat', String(coords.latitude))
                .set('lon', String(coords.longitude))
                .set('units', 'metrics')
                .set('appid', '......')
            }),
            switchMap(params => this.http.get<OpenWeatherResponse>(this.url, {params})),
            pluck('list'),
            mergeMap(value => of(...value)),
            filter((value, index) => index % 8 === 0),
            map(value => {
              return {
                dateString: value.dt_txt,
                temp: value.main.temp
              }
            }),
            toArray(),
            share()
          )
      }
    
      getCurrentLocation() {
//looking to call as a first method and need to save in variable
        return new Observable<GeolocationCoordinates>(observer => {
          window.navigator.geolocation.getCurrentPosition(
            position => {
              observer.next(position.coords);
              observer.complete();
            },
            err => observer.error(err)
          )
        }).pipe(
          retry(1),
          tap({
            next: () => this.notificationService.addSuccess('Got your location'),
            error: catchError((err) => {
              this.notificationService.addError('Failed to get the location');
              return throwError(() => new Error(err));
            })
          }))
      }
    
    }

Please check my comments for my requirements.


Solution

  • You can create a shared observable and add caching using shareReplay to avoid calling the api each time

    headers$ = this.getCurrentLocation().pipe(
       map(coords => {
              return new HttpParams()
                .set('lat', String(coords.latitude))
                .set('lon', String(coords.longitude))
                .set('units', 'metrics')
                .set('appid', '.......')
       }),
       shareReplay(1) // caching
    )
    

    and then use it that way

    getForecast() {
       this.headers$.pipe(
         switchMap(params => this.http.get<OpenWeatherResponse>(this.url, {params})),
         pluck('list'),
         ...
       )
    }