0

In previous applications using either Angular 8 and 9, I was using class-based actions rather than action creators. This time around, I decided to try using action creators instead. However, I've run into a hitch: where I previously used this.dataPersistence.navigation(...) for async methods and success actions to execute based on navigation, it's now wrapped in createEffect(() => ...) but it doesn't seem to work (whether it's wrapped or not)

Here's the setup and most of this is boilerplate:

package.json

"@nrwl/angular": "9.2.4",
...
"@angular/cli": "9.1.0",
"@nrwl/workspace": "9.2.4",

action.ts

export const setActivePanelId = createAction('[Interactions] Set Active Panel ID', props<{ id: string }>());

app.routes

const routes: Routes = [
  {
    path: '',
    component: MessagesContainer
  }
];

interactions.effects.ts

 onNav$ = createEffect(() =>
    this.dataPersistence.navigation(MessagesContainer, {
      run: (a: ActivatedRouteSnapshot): Observable<Action> | Action | void => {
        //An example callback, no async used yet.
        return setActivePanelId({id: a['snapshot'].queryParams.panelId});
      },
      onError: (a: ActivatedRouteSnapshot, e: any): any => {
        console.warn(e);
      }
    }));

app.module.ts

@NgModule({
  declarations: [AppComponent, MessagesContainer],
  imports: [
    BrowserModule,
    ComponentsModule,
    RouterModule.forRoot(routes, routingOptions),
    EffectsModule.forRoot([]),
    NxModule.forRoot(),
    StoreRouterConnectingModule.forRoot(),
    StoreModule.forRoot({}, { metaReducers: [] }),
    StoreDevtoolsModule.instrument({
      maxAge: 20,
      logOnly: config.environment.production
    }),
    InteractionsModule
  ],
  bootstrap: [AppComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {
}

interactions.module.ts

@NgModule({
  imports: [
    CommonModule,
    StoreModule.forFeature(
      fromInteractions.INTERACTIONS_FEATURE_KEY,
      fromInteractions.reducer
    ),
    EffectsModule.forFeature([InteractionsEffects]),
    StoreModule.forFeature(
      fromInteractions.INTERACTIONS_FEATURE_KEY,
      fromInteractions.reducer
    )
  ],
  providers: [InteractionsFacade]
})
export class InteractionsModule {}

UPDATE: I've also tried

@Effect() nav$ = createEffect(() =>
    this.actions$.pipe(
      // listens for the routerNavigation action from @ngrx/router-store
      navigation(MessagesContainer, {
        run: (activatedRouteSnapshot: ActivatedRouteSnapshot) => {
          return setActivePanelId({id: 'async!'});
        },

        onError: (
          activatedRouteSnapshot: ActivatedRouteSnapshot,
          error: any
        ) => {
          // we can log and error here and return null
          // we can also navigate back
          console.warn(error)
          return null;
        }
      })
    )
  );
  • An immediate workaround that's working for me is adding an effect that watches for ngrx's navigation. `export const onNav = createAction('@ngrx/router-store/navigated', props<{payload: any}>());` It gives me access to the router state post-navigation, but it does require logic within the effect to check which route I'm on. Fewer actions need to be created, but the logic of discerning which route I'm on must be done in the effect. – James Slater May 12 '20 at 13:19
  • I've had to downgrade everything to 9.0.2 in my package.json to get datapersistence.navigation to work properly. – James Slater May 18 '20 at 13:22

2 Answers2

3

Kindly refer https://nx.dev/latest/angular/guides/misc-data-persistence The StoreRouterConnectingModule must be configured with an appropriate serializer. The DefaultRouterStateSerializer provides the full router state instead of the MinimalRouterStateSerializer that is used without configuration.

import { NgModule } from '@angular/core';
import {
  StoreRouterConnectingModule,
  DefaultRouterStateSerializer,
} from '@ngrx/router-store';

@NgModule({
  imports: [
    StoreRouterConnectingModule.forRoot({
      serializer: DefaultRouterStateSerializer,
    }),
  ],
})
export class TodosModule {}
  • Surprised that this answer exactly works for me. I'm also facing the same problem as described in this post while updating ngrx from version 8 to later in nx workspace. It seems that DefaultRouterStateSerializer exactly needs to be written explicitly, which seems that DefaultRouterStateSerializer is not default here. – 千木郷 Sep 13 '21 at 14:19
1

My first instinct is to ask if you have NxModule.forRoot() imported anywhere? I typically put that in my app root module.

Aside from that, if you stick with this pattern:

onNav$ = createEffect(() =>
this.dataPersistence.navigation(MessagesContainer, {

you are doing it correctly.

Here is very similar (working) code from another project I'm working on:

`selectCustomer$ = createEffect(() =>
    this.dataPersistence.navigation(CustomerDetailComponent, {
        run: (
            r: ActivatedRouteSnapshot,
            _state: CustomerDetailPartialState
        ) => {
            const customerId = grabIdFromParams(r.paramMap);

            return CustomerDetailActions.customerSelected({ customerId });
        },
        onError: (_a: ActivatedRouteSnapshot, error: any) => {
            throw new Error(error);
        }
    })
);`

Unfortunately I don't have any other suggestions. I hope that helps or someone else has something better. Best of luck!

Jesse
  • 2,391
  • 14
  • 15
  • I appreciate your feedback regardless! Yes, I have `NxModule.forRoot()` in the app.module. Incidentally, even the old way (e.g. `@effect() nav$ = this.dataPersistence.navigation`) isn't working either. I can only imagine there's something else going on that doesn't meet the eye. Fortunately I have functioning projects to compare against, so I can compare line by line. – James Slater May 12 '20 at 13:12
  • Thanks! I ran into a dependency issue on a newer project with it-- but those were actual errors being thrown in the console when I tried to build. Fixing it involved copy pasting the data-persistence.ts file from github directly into my project (it's only one file). Not saying you should do that, but it's an option if you need to really step through some source code. I hope you figure it out! – Jesse May 12 '20 at 13:31