1

how to subscribe to response when tap operator is used in the service.

Have anyone know how to resolve this?

edit(status) {
    dataObj.val = status;
    // call post service with status..
    this.service
        .update(dataObj)
        .pipe(takeUntil(this._ngUnsubscribe$))
        .subscribe(() => {
            //i would like to wait until response come from backend and then navigate to the page so i                get data over there.
            if (res.status === 'Success') {
                this.router
                    .navigate(['../../success'], {
                        relativeTo: this.route,
                    })
                    .then(() => {});
            } else {
                this.location.back();
            }
        });
}

//akita store service

update(
    obj: any,
): Observable < any > {
    return this.service.update(obj).pipe(
        delay(800),
        map((data: RestfulResponse < any > ) => data.data),
        tap((data: anny) => {
            this.store.update((state) => {
                state.updateValue = data; // value is not updating and it is navigating to route
            });
        }),
    );
}

//post service

update(obj){
//post call
}

Is there any way I can use tap and in service side and subscribe on component side?

I know I can use finalize but it is not helping for writing conditions inside.

app
  • 197
  • 8
  • 24

1 Answers1

1

The tap operator, by design, handles side effects which don't happen within the context of your observable pipeline. This means that your pipeline will never wait for results from the tap itself. I don't recommend using it in this manner. Under most circumstances, I only use tap for debugging.

If you are waiting for a particular state change, you should create a separate observable, selecting from your store, to watch the state for the expected change.

If you want to trigger an additional action when something happens, I recommend using ngrx Effects to achieve this.

Have a look at this post, where I talked about how to implement a similar use case: https://stackoverflow.com/a/64491398/166850

You should also strive to set up reducers that apply your state changes, rather than updating the store directly.

Consider each of the following as a separate concern that you can implement independently of the others:

  1. When user does an edit, trigger an edit action.
  2. The reducer should update the state based on the edit action (for example, to show that a save is in progress)
  3. When the edit action is triggered, trigger an effect. The app should make an HTTP call to save the change, then trigger a save finished action.
  4. When the save is finished, the router navigation should be triggered.

This separates your code into multiple units which are easy to test and verify independently.

If #1 produces an action which is consumed by your reducer (#2), you can also create an ngrx Effect for #3 which listens for the same action, handles the HTTP call using switchMap, then triggers another action to signal that it's done.

Edit

Here's a simple example. The first time an action called APP_LOADED is triggered (from the AppComponent), this Effect makes an HTTP call to get data from the server, then triggers an action using the response data as the action payload.

The actual HTTP call is delegated to another service, the HttpMyConfigDataService, which simply calls HttpClient and returns an Observable.

@Injectable({
  providedIn: 'root'
})
export class LoadMyConfigEffect {
  constructor(
    private httpMyConfigDataService: HttpMyConfigDataService,
    private action$: Actions
  ) {
  }

  loadMyConfigData$ = createEffect(() => {
    return this.action$.pipe(
      filter((action) => action.type === 'APP_LOADED'),
      take(1),
      switchMap(() => this.httpMyConfigDataService.get().pipe(
        map(data => {
          return {type: 'MY_CONFIG_DATA_LOADED', payload: data};
        }),
        catchError(err => {
          console.error('Error loading config data.', err);
          return of({type: 'CONFIG_LOAD_ERROR', payload: err.message, isError: true);
        })
      ))
    );
  });
}
RMorrisey
  • 7,637
  • 9
  • 53
  • 71