Effects & Selectors — Series 3

Preview — 3 of 10 questions

What does the { functional: true } option, combined with inject() calls inside the factory function, actually change here compared to the older class-based effect style?

javascript
export const loadCartEffect = createEffect(
  () => {
    const actions$ = inject(Actions);
    const cartService = inject(CartService);
    return actions$.pipe(
      ofType(loadCart),
      switchMap(() => cartService.getCart().pipe(map(cart => loadCartSuccess({ cart })))),
    );
  },
  { functional: true },
);
AFunctional effects don't require an enclosing @Injectable() class with a constructor injecting Actions and any needed services — the effect is just a standalone function using inject() for its dependencies, registered directly (e.g., via provideEffects({ loadCartEffect })). It's the same underlying effects mechanism, just without the class-based ceremony, mirroring the shift toward functional guards, resolvers, and interceptors elsewhere in modern Angular
BNothing functionally different — { functional: true } is purely a linting hint with no effect on how the effect actually runs
CFunctional effects run synchronously, unlike class-based ones which are always asynchronous
D{ functional: true } disables the requirement for ofType, letting the effect react to every dispatched action automatically

What do selectAll, selectEntities, selectIds, and selectTotal actually do here?

javascript
export const heroAdapter = createEntityAdapter<Hero>();
export const { selectAll, selectEntities, selectIds, selectTotal } = heroAdapter.getSelectors();
AgetSelectors() generates a standard, ready-to-use set of selector functions matched to the normalized entity state shape the adapter manages — selectAll (every entity as an array), selectEntities (the raw id-to-entity dictionary), selectIds (just the ids, in order), and selectTotal (a count) — without needing to hand-write any of these common, repetitive selectors yourself for every entity-shaped slice of state
BThey're placeholder names that still need to be manually implemented by the developer before use
CThese selectors only work when combined with @ngrx/effects, not @ngrx/store alone
DgetSelectors() requires passing the feature's createFeatureSelector result as an argument; it cannot be called with no arguments

Where is catchError placed here, and why does that placement matter for whether the effect keeps working after a failed request?

javascript
export const loadHeroEffect = createEffect(() =>
  this.actions$.pipe(
    ofType(loadHero),
    switchMap(({ id }) =>
      this.heroService.getHero(id).pipe(
        map(hero => loadHeroSuccess({ hero })),
        catchError(() => of(loadHeroFailure())),
      ),
    ),
  ),
);
AIt doesn't matter where catchError is placed; any position in the pipe has the same effect
BcatchError inside switchMap only catches synchronous errors, not asynchronous HTTP failures
CThis code is broken regardless of catchError's placement, since switchMap cannot be combined with error handling at all
DcatchError is placed inside switchMap's inner pipe, scoped to just that one HTTP call's Observable — a failure there is caught and converted into a normal loadHeroFailure() emission before it ever reaches the outer actions$.pipe(...). This means the outer stream never sees an error at all, and keeps processing future loadHero actions with nothing lost. Had catchError been placed on the outer pipe instead, an error would still tear down that stream — NgRx would report it and resubscribe (since v8), but the action that failed is dropped and the whole effect restarts, so an error can never be turned into a clean loadHeroFailure() there

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.