Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EffectsModule.forFeature() fails to load in a eagerly loaded module #400

Closed
Lycidas0815 opened this issue Sep 18, 2017 · 9 comments
Closed

Comments

@Lycidas0815
Copy link

Lycidas0815 commented Sep 18, 2017

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Feature request
[ ] Documentation issue or request

What is the current behavior?

EffectsModule.forFeature() fails to load in a eagerly loaded module, missing providers. Works in a lazy or pre loaded module.

Expected behavior:

EffectsModule.forFeature() works, no matter with which loading strategy it is used.

Minimal reproduction of the problem with instructions:

I have a lazy/pre loaded module with the following setup:

imports: [
  StoreModule.forFeature('vehicles', reducers),
  EffectsModule.forFeature([VehicleEffects]),
],
providers; [
  VehicleExistsGuard, VehicleService,
]

with an effect class (functions omitted)

@Injectable()
export class VehicleEffects {
  constructor(
    private actions$: Actions,
    private vehicleService: VehicleService,
  ) {}
}

As soon as I load that module eagerly (app.module or core.module), my application crashes with a
zone.js:661 Unhandled Promise rejection: No provider for String!

This is caused by the effects constructor which needs the VehicleService injected. I read in the effects documentation that EffectsModule.forFeature() is basically the same function as EffectsModule.forRoot() except the fact that the providers aren't loaded.
This is exactly what I am experiencing; but how am I supposed to load that module correctly if needed eagerly (which might change again)?

Using EffectsModule.forRoot() does
a.) not feel right to use in a feature module and
b.) does not work either. The app starts but the effect does not fire (SearchAction is dispatched, effect should react to that, call the service and dispatch a SearchSuccess/SearchFailed action).

The only workaround I can see now is to include Service/Guard in the providers section of my app.module and to load the VehicleEffect in the app.module with EffectsModule.forRoot([VehicleEffects]),.
Since I have another 10-20 modules where the (future) usage patterns will determine the loading strategy for each module, it is not acceptable to pollute my app-module like that.

I want to be able to either load (the store related parts of) the module eagerly in my core-module or let it be loaded/pre-loaded as needed.

Any advice will be greatly appreciated.
Thanks,
Ly

/Edit:
Another workaround/solution I just realized is to use a static forRoot() in my core-module, returning a ModuleWithProviders and calling that in my app-module. That will register all needed providers properly and I can start to use EffectsModule.forFeature() again. Might be sufficient for now but does not solve the underlying problem that a module behaves differently, depending on the loading strategy.

Version of affected browser(s),operating system(s), npm, node and ngrx:

Other information:

@brandonroberts
Copy link
Member

This is not a bug. EffectsModule.forRoot is required to wire up application level providers and must be registered only once before EffectsModule.forFeature is used. You can provide forRoot with an empty array if you don't need to register any effects in the root.

@Lycidas0815
Copy link
Author

Thanks for your fast reply, but your answer does not tackle my problem.

Of course I am using EffectsModule.forRoot with an empty array to wire up the application level providers (which are empty in this case).
My statement is, that it is not possible to add providers at the FEATURE level if the feature module is loaded eagerly. If loaded lazy, everything works as expected. It is possible and perfectly feasible to add reducers at the feature level, even if loaded eagerly, but not effects which in turn require providers.

For EffectsModule.forFeature to work in a eagerly loaded module, all required providers have to be already available at the application level. That is not the case if the module is lazy loaded.

Thanks,
Ly

@brandonroberts
Copy link
Member

Ok. Can you provide a reproduction of this? We are using the exact scenario you describe in the example app with no issues. The AuthModule is eagerly loaded with its own providers and effects.

https://github.com/ngrx/platform/blob/master/example-app/app/auth/auth.module.ts

https://github.com/ngrx/platform/blob/master/example-app/app/app.module.ts#L79

@Lycidas0815
Copy link
Author

I think that was a misunderstanding on my side. I was somehow expecting that a lazy loaded module can be used eagerly without any modifications. That seems to be not the case, which is caused by Angular, not ngrx itself. Adding a forRoot() to the module is sufficient, like in your AuthModule case.
Without that the include order seems to be off.

Thanks anyways, I learned alot again.

Ly

@brandonroberts
Copy link
Member

Lazy loaded modules can be used eagerly, just remember that your providers need to be registered with the module. Using forRoot is a pattern to separate the application level providers from the module. It makes the module easier to reuse without re-registering service providers. You can put your providers in the metadata of the NgModule just the same though.

@amitcdubey
Copy link

can anyone help me for below issue.
am using EffectsModule.forFeature in my module.ts and also using entryComponents but when am going to use ng test its not working test is not executing .

@sahrmann
Copy link

sahrmann commented Dec 5, 2018

@Lycidas0815 Thanks for your post. It is interesting that you say everything works fine with a lazy loaded module. I currently have an application with the exact same situation as in your minimal example. Except that lazy loading the module causes the "No provider for BackendService" error. Do you have a project set up where the lazy loading works?

@directcuteo
Copy link

@brandonroberts can you explain to me why does the Effects injectable class in a feature module get instantiated at the application load and not at the lazy-loaded module load? I can console.log something in the Effects constructor and I can see that log even if the feature module is not loaded. Thanks!

@brandonroberts
Copy link
Member

@directcuteo this is in our docs already right above here https://ngrx.io/guide/effects#registering-feature-effects

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants