Reputation: 105029
I have a feature module that declares my components and also has a static function that configures feature routing.
@NgModule({
declarations: FEATURE_COMPONENTS,
entryComponents: FEATURE_COMPONENTS,
imports: [
UIRouterModule,
...
]
})
export class FeatureModule {
public static setParentState(stateName: string): ModuleWithProviders {
...
return {
ngModule: FeatureModule,
providers: [
...UIRouterModule.forChild({ states: ... }).providers
// my providers
{
provide: FEATURE_PROVIDER_TOKEN,
useValue: ...
multi: false
}
]
};
}
}
My module on its own isn't enough to actually use the features, it also needs routing configuration which is done correctly through upper static function.
I would like to prevent this scenario:
@NgModule({
...
imports: [
// invalid import - I want to prevent this one
FeatureModule
// valid import
FeatureModule.setParentState(...)
]
})
export class SomeAppModule {}
How can I throw some error when user tries to import my feature module directly as per above code? Correct import would be through calling the static function and not directly...
One of the possible things I might be able to use is the extra provider I'm adding my static function. But how? Via module constructor and its injections? Maybe via some custom decorator?
I was thinking of doing it this way somehow, but would also like to provide some custom error message with information how to correctly import the module:
@NgModule({ ... })
export class FeatureModule {
public static setParentState(stateName: string): ModuleWithProviders {
// FEATURE_PROVIDER_TOKEN defined here (see above)
...
}
constructor(
@Import(FEATURE_PROVIDER_TOKEN) tokenTest: any
} {
// this will throw an error when provider isn't defined, but won't allow me to set specific error message
}
}
Any ideas?
Upvotes: 1
Views: 1240
Reputation: 105029
This is what I've implemented and it seems to satisfy the requirements:
This is how it's implemented:
const PREVENT_DIRECT_IMPORT: InjectionToken<boolean> = new InjectionToken('FeatureModule:PREVENT_DIRECT_IMPORT');
@NgModule({
declarations: FEATURE_COMPONENTS,
entryComponents: FEATURE_COMPONENTS,
imports: [ ... ],
exports: [ ... ]
providers: [{
// erroneous provider when module is directly imported
provide: PREVENT_DIRECT_IMPORT,
useFactory: () => { throw new Error('Correct usage info'); },
multi: false
}]
})
export class FeatureModule {
public static setParentState(stateName: string): ModuleWithProviders {
...
return {
ngModule: FeatureModule,
providers: [
...UIRouterModule.forChild({ states: ... }).providers
// my providers
{
provide: FEATURE_PROVIDER_TOKEN,
useValue: ...
multi: false
}, {
// this is the same provider when module is correctly imported
provide: PREVENT_DIRECT_IMPORT,
useValue: true,
multi: false
}
]
};
}
constructor(
@Import(PREVENT_DIRECT_IMPORT) prevent: boolean
) {
// direct import will throw error when DI tries to get the injected provider
}
}
Upvotes: 2