Search code examples
angulartypescriptrxjs

Observable on route params stops observing after 404 error from another Observable in switchmap


In my situation, I'm observing the parameters used in the active route to update the content I'm displaying.

In my component, ngOnInit() function, I have something like this :

this.activeRoute.paramMap
      .pipe(
        switchMap((params) => {
          this.fileName = String(params.get('filePath'));
          return this.fileService.checkIfFileExists(this.fileName);
        }),
        tap((result) => {
          if (!result) {
            this.router.navigate(['/']);
          }
        }),
        filter((result) => result),
        switchMap(() =>
          this.modificationService.getFileModifications(this.fileName)
        ),
        tap((result) => {
          if (result.allModifications) {
            this.modificationList = result.allModifications;
            this.noModification = false;
          }
        })
      )
      .subscribe();

For more context :

  • If the file doesn't exist : the router redirect user to /
  • If the file exists, there are two possibilities :
    • There are modifications found : we display it
    • There are no modification, a 404 error is sent, and it's normal, the website should display "no modifications found"

Currently, the behavior is :

  • If I go on a page for a file that has modifications, they are displayed
  • If I switch to whichever file that also has modifications, same, it's updated, the modifications are displayed, all good
  • If I switch to a file that has no modification, and thus, send a 404, the observable stops working. The content is stuck on the last file with modification displayed, even if the URL (and so does the filePath param) changes

I switch from file to file using a menu, I never refresh the page, If I refresh it's working.

I have tried to use the catchError() from RxJS, the only difference is that the error is no longer in the console, the behavior stays the same.

I used to only have a

this.router.routeReuseStrategy.shouldReuseRoute = () => false;

Instead of the this.activeRoute.paramMap... it's actually deprecated, I don't want to use it. The paramMap Observer works perfectly with my other component that doesn't have to manage 404 error

Any help will be welcomed :)


Solution

  • The 404 response from modificationService is causing your stream to complete. The switchMap operator switches over to the inner stream, so anything that makes it complete, completes the outer stream. In this case, the 404 response is emitting as an error, which completes the inner stream.

    Once a stream completes, its essentially static, so it will ignore any future emissions. The trick to getting around this is to catch the error and return a stream to keep the error from surfacing.

    this.activeRoute.paramMap
      .pipe(
        switchMap((params) => {
          this.fileName = String(params.get("filePath"));
          return this.fileService.checkIfFileExists(this.fileName);
        }),
        tap((result) => {
          if (!result) {
            this.router.navigate(["/"]);
          }
        }),
        filter((result) => result),
        switchMap(() =>
          this.modificationService
          .getFileModifications(this.fileName)
                .pipe(
                  // prevents the complete and returns a new observable
                  catchError((err) => {
                    console.error(err);
                    return of(null);
                  })
                )
        ),
        tap((result) => {
          if (result.allModifications) {
            this.modificationList = result.allModifications;
            this.noModification = false;
          }
        })
      )
      .subscribe();