title: Angular route guards doesn't work as expected when returning Observable
body: <p>So i have this code:</p>
  <p>Basically this guard listens for the occurence of certain success and failure ngrx actions and i map it to their boolean equivalents. But for some reason this doesn't work as expected.</p>
  <p>Doesn't <code>ofType</code> rxjs operator gets executed once a target action gets dispatched w/c i believe should work in the code below. I use <code>mapTo</code> operator to map success action to boolean true and false to failure action.</p>
  <p><strong>bookmark-must-exist.guard.ts</strong></p>
  <pre class="lang-js prettyprint-override"><code>    import { Injectable } from '@angular/core';
      import {
        CanActivate,
        ActivatedRouteSnapshot,
        RouterStateSnapshot,
        Router,
      } from '@angular/router';
      import { Observable, merge, race, of } from 'rxjs';
      import { Store } from '@ngrx/store';
      import { Actions, ofType } from '@ngrx/effects';
      import { take, mapTo, tap, switchMap } from 'rxjs/operators';
      
      import * as bookmarkActions from '@app/features/bookmarks/state/actions/bookmarks.actions';
      
      @Injectable({
        providedIn: 'root',
      })
      export class BookmarkMustExistGuard implements CanActivate {
        constructor(
          private store: Store,
          private actions$: Actions,
          private router: Router
        ) {}
      
        canActivate(
          route: ActivatedRouteSnapshot,
          state: RouterStateSnapshot
        ): Observable&lt;boolean&gt; {
          const bookmarkId = route.params.id;
          this.store.dispatch(
            bookmarkActions.selectOrLoadBookmark({ id: bookmarkId })
          );
      
          const successAction$ = this.actions$.pipe(
            ofType(
              bookmarkActions.selectBookmarkInStoreSuccess
              bookmarkActions.loadBookmarkFromApiSuccess
            ),
            mapTo(true),
            take(1)
          );
      
          const failureAction$ = this.actions$.pipe(
            ofType(bookmarkActions.loadBookmarksFailure),
            mapTo(false),
            take(1)
          );
          return race(successAction$, failureAction$).pipe(
            tap(value =&gt; {
              if (!value) {
                this.router.navigateByUrl('/not-found');
              }
            }),
            take(1)
          );
        }
      }
  </code></pre>
  <p>It seems like the observables from <code>ofType</code> inside the guard doesn't complete even if i add a <code>take(1)</code> operator</p>
  <p>Btw, this is the routing module for the <strong>lazy-loaded</strong> module</p>
  <pre class="lang-js prettyprint-override"><code>import { NgModule } from '@angular/core';
  import { Routes, RouterModule } from '@angular/router';
  
  import { BookmarkMustExistGuard } from './guards/bookmark-must-exist.guard';
  import { BookmarksPageComponent } from './containers/bookmarks-page/bookmarks-page.component';
  import { BookmarksCurrentListContainerComponent } from './containers/bookmarks-current-list-container-container/bookmarks-current-list-container.component';
  import { BookmarkSearchResultsContainerComponent } from './containers/bookmark-search-results-container/bookmark-search-results-container.component';
  import { BookmarkArchivesContainerComponent } from './containers/bookmark-archives-container/bookmark-archives-container.component';
  import { BookmarkFavoritesContainerComponent } from './containers/bookmark-favorites-container/bookmark-favorites-container.component';
  import { BookmarksByTagContainerComponent } from './containers/bookmarks-by-tag-container/bookmarks-by-tag-container.component';
  import { BookmarkReaderViewPageComponent } from './containers/bookmark-reader-view-page/bookmark-reader-view-page.component';
  
  const routes: Routes = [
    {
      path: '',
      component: BookmarksPageComponent,
      children: [
        {
          path: '',
          component: BookmarksCurrentListContainerComponent,
          data: {
            reuseRoute: true,
          },
        },
        {
          path: 'search',
          component: BookmarkSearchResultsContainerComponent,
        },
        {
          path: 'archives',
          component: BookmarkArchivesContainerComponent,
        },
        {
          path: 'favorites',
          component: BookmarkFavoritesContainerComponent,
        },
        {
          path: 'tags/:name',
          component: BookmarksByTagContainerComponent,
        },
      ],
    },
    {
      path: 'reader/:id',
      component: BookmarkReaderViewPageComponent,
      canActivate: [BookmarkMustExistGuard],
    },
  ];
  
  @NgModule({
    imports: [RouterModule.forChild(routes)],
    exports: [RouterModule],
  })
  export class BookmarksRoutingModule {}
  </code></pre>
  <p>here's the relevant effect</p>
  <pre class="lang-js prettyprint-override"><code>  selectOrLoadBookmark$ = createEffect(() =&gt; {
      return this.actions$.pipe(
        ofType(bookmarkActions.selectOrLoadBookmark),
        switchMap(({ id }) =&gt; {
          return of(id).pipe(
            withLatestFrom(
              this.store.select(bookmarksSelectors.selectCurrentBookmark(id))
            )
          );
        }),
        switchMap(([id, bookmarkInStore]) =&gt; {
          console.log({ id, bookmarkInStore });
          const bookmarkFromApi$ = this.bookmarksService.getBookmark(id).pipe(
            map(({ bookmark }) =&gt; {
              return bookmarkActions.loadBookmarkFromApiSuccess({
                bookmark,
              });
            }),
            catchError(error =&gt;
              of(
                bookmarkActions.loadBookmarkFromApiFailure({
                  error: error?.error?.message,
                })
              )
            )
          );
  
          const bookmarkFromStore = bookmarkActions.selectBookmarkInStoreSuccess({
            bookmark: bookmarkInStore,
          });
  
          // if (!!bookmarkInStore) {
          // return of(bookmarkFromStore);
          // }
          // return bookmarkFromApi$;
  
          return iif(
            () =&gt; !!bookmarkInStore,
            of(bookmarkFromStore),
            bookmarkFromApi$
          );
        })
      );
    });
  </code></pre>