diff --git a/modules/effects/spec/integration.spec.ts b/modules/effects/spec/integration.spec.ts index e986f78729..fe572774c1 100644 --- a/modules/effects/spec/integration.spec.ts +++ b/modules/effects/spec/integration.spec.ts @@ -1,22 +1,18 @@ -import { - NgModuleFactoryLoader, - NgModule, - InjectionToken, - Type, -} from '@angular/core'; +import { NgModule, NgModuleFactoryLoader } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { RouterTestingModule, SpyNgModuleFactoryLoader, } from '@angular/router/testing'; import { Router } from '@angular/router'; -import { Store, Action } from '@ngrx/store'; +import { Action, Store } from '@ngrx/store'; import { EffectsModule, + EffectSources, + OnIdentifyEffects, OnInitEffects, ROOT_EFFECTS_INIT, - OnIdentifyEffects, - EffectSources, + USER_PROVIDED_FEATURE_EFFECTS, } from '..'; describe('NgRx Effects Integration spec', () => { @@ -100,16 +96,16 @@ describe('NgRx Effects Integration spec', () => { }); }); - it('should execute injected effects', (done: DoneFn) => { + it('should execute user provided effects', (done: DoneFn) => { let router: Router = TestBed.get(Router); const loader: SpyNgModuleFactoryLoader = TestBed.get(NgModuleFactoryLoader); - loader.stubbedModules = { feature: FeatModuleWithInjectedEffects }; + loader.stubbedModules = { feature: FeatModuleWithUserProvidedEffects }; router.resetConfig([{ path: 'feature-path', loadChildren: 'feature' }]); router.navigateByUrl('/feature-path').then(() => { expect(dispatch).toHaveBeenCalledWith({ - type: '[FeatEffectWithInjection]: INIT', + type: '[FeatUserProvidedEffect]: INIT', }); done(); }); @@ -153,30 +149,27 @@ describe('NgRx Effects Integration spec', () => { constructor(private effectIdentifier: string) {} } - class FeatEffectWithInjection implements OnInitEffects { + class FeatUserProvidedEffect implements OnInitEffects { ngrxOnInitEffects(): Action { - return { type: '[FeatEffectWithInjection]: INIT' }; + return { type: '[FeatUserProvidedEffect]: INIT' }; } } @NgModule({ - imports: [EffectsModule.forRoot([])], + imports: [EffectsModule.forRoot()], }) class FeatModuleWithForRoot {} - const FEATURE_INJECTED_EFFECTS_TOKEN = new InjectionToken[]>( - 'FEATURE_INJECTED_EFFECTS_TOKEN' - ); - @NgModule({ - imports: [EffectsModule.forFeature(FEATURE_INJECTED_EFFECTS_TOKEN)], + imports: [EffectsModule.forFeature()], providers: [ - FeatEffectWithInjection, + FeatUserProvidedEffect, { - provide: FEATURE_INJECTED_EFFECTS_TOKEN, - useValue: [FeatEffectWithInjection], + provide: USER_PROVIDED_FEATURE_EFFECTS, + multi: true, + useValue: [FeatUserProvidedEffect], }, ], }) - class FeatModuleWithInjectedEffects {} + class FeatModuleWithUserProvidedEffects {} }); diff --git a/modules/effects/src/effects_module.ts b/modules/effects/src/effects_module.ts index 979579b12c..b1b814c67a 100644 --- a/modules/effects/src/effects_module.ts +++ b/modules/effects/src/effects_module.ts @@ -1,6 +1,4 @@ import { - Inject, - InjectionToken, Injector, ModuleWithProviders, NgModule, @@ -12,10 +10,12 @@ import { EffectSources } from './effect_sources'; import { Actions } from './actions'; import { _FEATURE_EFFECTS, - _FEATURE_EFFECTS_TOKEN, + _ROOT_EFFECTS, _ROOT_EFFECTS_GUARD, FEATURE_EFFECTS, ROOT_EFFECTS, + USER_PROVIDED_FEATURE_EFFECTS, + USER_PROVIDED_ROOT_EFFECTS, } from './tokens'; import { EffectsFeatureModule } from './effects_feature_module'; import { EffectsRootModule } from './effects_root_module'; @@ -24,37 +24,33 @@ import { EffectsRunner } from './effects_runner'; @NgModule({}) export class EffectsModule { static forFeature( - featureEffects: Type[] | InjectionToken[]> + featureEffects: Type[] = [] ): ModuleWithProviders { return { ngModule: EffectsFeatureModule, providers: [ - featureEffects instanceof InjectionToken ? [] : featureEffects, - { provide: _FEATURE_EFFECTS, multi: true, useValue: featureEffects }, + featureEffects, { - provide: _FEATURE_EFFECTS_TOKEN, + provide: USER_PROVIDED_FEATURE_EFFECTS, multi: true, - useExisting: - featureEffects instanceof InjectionToken - ? featureEffects - : _FEATURE_EFFECTS, + useValue: [], + }, + { + provide: _FEATURE_EFFECTS, + useValue: featureEffects, }, { provide: FEATURE_EFFECTS, multi: true, - deps: [ - Injector, - _FEATURE_EFFECTS, - [new Inject(_FEATURE_EFFECTS_TOKEN)], - ], - useFactory: _createFeatureEffects, + useFactory: createEffects, + deps: [Injector, _FEATURE_EFFECTS, USER_PROVIDED_FEATURE_EFFECTS], }, ], }; } static forRoot( - rootEffects: Type[] + rootEffects: Type[] = [] ): ModuleWithProviders { return { ngModule: EffectsRootModule, @@ -68,27 +64,48 @@ export class EffectsModule { EffectSources, Actions, rootEffects, + { + provide: USER_PROVIDED_ROOT_EFFECTS, + multi: true, + useValue: [], + }, + { + provide: _ROOT_EFFECTS, + useValue: rootEffects, + }, { provide: ROOT_EFFECTS, - deps: rootEffects, - useFactory: createSourceInstances, + useFactory: createEffects, + deps: [Injector, _ROOT_EFFECTS, USER_PROVIDED_ROOT_EFFECTS], }, ], }; } } -export function createSourceInstances(...instances: any[]) { - return instances; +export function createEffects( + injector: Injector, + effects: Type[], + userProvidedEffectGroups: Type[][] +): any[] { + const mergedEffects: Type[] = effects; + userProvidedEffectGroups.forEach(group => mergedEffects.push(...group)); + return createSourceInstances( + ...createEffectInstances(injector, ...mergedEffects) + ); } export function createEffectInstances( injector: Injector, ...effects: Type[] -) { +): any[] { return effects.map(effect => injector.get(effect)); } +export function createSourceInstances(...instances: any[]) { + return instances; +} + export function _provideForRootGuard(runner: EffectsRunner): any { if (runner) { throw new TypeError( @@ -97,22 +114,3 @@ export function _provideForRootGuard(runner: EffectsRunner): any { } return 'guarded'; } - -export function _createFeatureEffects( - injector: Injector, - effectCollections: Type[][] | InjectionToken[]>[] -): any[] { - const effects: Type[] = []; - - effectCollections.forEach( - (effectCollection: Type[] | InjectionToken[]>) => { - effects.push( - ...(effectCollection instanceof InjectionToken - ? injector.get(effectCollection) - : effectCollection) - ); - } - ); - - return createSourceInstances(...createEffectInstances(injector, ...effects)); -} diff --git a/modules/effects/src/index.ts b/modules/effects/src/index.ts index 8b0f731ee6..563c2ee205 100644 --- a/modules/effects/src/index.ts +++ b/modules/effects/src/index.ts @@ -8,13 +8,14 @@ export { Actions, ofType } from './actions'; export { EffectsModule } from './effects_module'; export { EffectSources } from './effect_sources'; export { EffectNotification } from './effect_notification'; -export { - ROOT_EFFECTS_INIT, - rootEffectsInit, -} from './effects_root_module'; +export { ROOT_EFFECTS_INIT, rootEffectsInit } from './effects_root_module'; export { act } from './act'; export { OnIdentifyEffects, OnRunEffects, OnInitEffects, } from './lifecycle_hooks'; +export { + USER_PROVIDED_ROOT_EFFECTS, + USER_PROVIDED_FEATURE_EFFECTS, +} from './tokens'; diff --git a/modules/effects/src/tokens.ts b/modules/effects/src/tokens.ts index 2cf193a2dd..e75bac85b7 100644 --- a/modules/effects/src/tokens.ts +++ b/modules/effects/src/tokens.ts @@ -6,14 +6,20 @@ export const _ROOT_EFFECTS_GUARD = new InjectionToken( export const IMMEDIATE_EFFECTS = new InjectionToken( 'ngrx/effects: Immediate Effects' ); +export const USER_PROVIDED_ROOT_EFFECTS = new InjectionToken>( + 'ngrx/effects: User Provided Root Effects' +); +export const _ROOT_EFFECTS = new InjectionToken[]>( + 'ngrx/effects: Internal Root Effects' +); export const ROOT_EFFECTS = new InjectionToken[]>( 'ngrx/effects: Root Effects' ); -export const _FEATURE_EFFECTS = new InjectionToken[][]>( - 'ngrx/effects: Internal Feature Effects' +export const USER_PROVIDED_FEATURE_EFFECTS = new InjectionToken[]>( + 'ngrx/effects: User Provided Feature Effects' ); -export const _FEATURE_EFFECTS_TOKEN = new InjectionToken[][]>( - 'ngrx/effects: Internal Feature Effects Token' +export const _FEATURE_EFFECTS = new InjectionToken[]>( + 'ngrx/effects: Internal Feature Effects' ); export const FEATURE_EFFECTS = new InjectionToken( 'ngrx/effects: Feature Effects'