0
votes

In my Angular app, I route to a component. Inside that component, I want to display an item$ observable.

Now, if my service has a cached item, use that, and regardless, request an item from the backend. So the experience might be to show the cached item for a moment, then the backend item replaces it after it loads. If the item doesn't exist on the backend, the cached item would be the only emitted value. If it's not, we show a not found.

Here's how I have tried to execute this:

  ngOnInit() {
    this.item$ = this.route.paramMap.pipe(
      switchMap((params: ParamMap) => {
        this.id = params.get('id'); // get the id
        if (this.service.item && this.id === this.service.item.id) {
          return of(this.service.item); // cached item
        }
        return of(null); // nothing cached
      }),
      merge(this.backend.getItem(this.id)) // get backend item
    );
  }

my template code

<div *ngIf="item$ | async as item; else showNotFound">
  <p>{{ item.name }}</p>
  <!-- other props omitted -->
</div>
<ng-template #showNotFound>
  <p>Not found</p>
</ng-template>

However, merge fires before switchMap and cannot get the item because this.id is not yet set. If I move the merge in front of switchMap, switchMap can't get the param. How can this be done?

2
You may try to remove merge altogether and place this.backend.getItem(this.id) within switchMap, as one of the Observable returned - Picci

2 Answers

0
votes

I supouse you want write

ngOnInit() {
    this.route.paramMap.pipe(
      switchMap((params: ParamMap) => {
        this.id = params.get('id'); // get the id
        if (this.service.item && this.id === this.service.item.id) {
          return of(this.service.item); // cached item
        }  
        //If not is cached
        return this.backend.getItem(this.id)
          //You can "cached" the value, here
          .pipe(tap((item)=>{this.service.item=item}
          ));
      })).subscribe((item)=>{this.item=item}); //DON'T forget subscribe
  }
0
votes

I was able to do it like this:

  ngOnInit() {
    this.item$ = this.route.paramMap.pipe(
      switchMap((params: ParamMap) => {
        this.id = params.get('id'); // get the id
        return this.backend.getItem(this.id).pipe(
          map(backendResult => {
            if (backendResult === undefined) {
              if (this.service.item && this.id === this.service.item.id) {
                return this.service.item; // cached item
              }
              return null; // nothing cached
            } else {
              return backendResult;
            }
          })
        );
      }),
    );
  }