I would like use provider value defined in other module. Here is example:
app.module.ts
...
import { ThemeModule } from '../shared/modules/theme/theme.module';
...
#NgModule({
declarations: [
RootComponent,
LoginScreenComponent,
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
BrowserAnimationsModule,
AppRoutingModule,
ConfigModule,
ThemeModule,
....
],
providers: [
...
{ provider: "THEME_NAME", useValue: "VALUE" },
],
bootstrap: [RootComponent]
})
export class MDMToolModule {}
theme.module.ts
import { NgModule } from '#angular/core';
import { ThemeService } from './services/ThemeService';
#NgModule({
imports: [],
declarations: [],
providers: [
{provide: "ThemeService", useFactory: (THEME_NAME) => {
return new ThemeService(THEME_NAME)
}},
],
exports: []
})
export class ThemeModule {}
Is there possibility to pass VALUE defied not in module like above example (THEME NAME)?
if you're providing value in root module then it will be available to all other modules too so you can then simply ask for that value using Inject decorator like this:
#Injectable()
export class ThemeService {
constructor(#Inject("THEME_NAME") theme: string) {}
}
otherwise you can import your MDMToolModule inside ThemeModule though judging by the code you provided I'm assuming this MDMToolModule is your root module,
you can also use Injection Token to avoid using those magic strings like this:
const ThemeName = new InjectionToken("token to inject theme name");
and then use it inside theme.module.ts
#NgModule({
providers: [
{ provide: ThemeName, useValue: "DarkKnight" },
ThemeService
]
})
export class ThemeModule {}
theme.service.ts
#Injectable()
export class ThemeService {
constructor(#Inject(ThemeName) theme: string) {}
}
I have created an interceptor to add the authentication token and refresh the authentication token if it expires like below:
#Injectable()
export class CustomInterceptors implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// ... implementation details
}
}
I have registered this interceptor in the main module of angular (app.module) like below:
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
RouterModule.forRoot(appRoutes),
HttpClientModule,
MatSnackBarModule,
// Fuse modules
FuseModule.forRoot(fuseConfig),
FuseProgressBarModule,
FuseSidebarModule,
FuseThemeOptionsModule,
// App modules
LayoutModule,
LightboxModule
],
bootstrap: [
AppComponent
],
providers: [AuthGuard, UsersService, ErrorService, {
provide: HTTP_INTERCEPTORS,
useClass: CustomInterceptors,
multi: true
}]
})
export class AppModule {
}
I have two lazy loaded modules AModule and BModule like below:
-- AModule
const routes: Routes = [
{
path: '**',
component: AComponent,
resolve: {
interventions: AService
}
}
];
#NgModule({
declarations: [
AComponent
],
imports: [
RouterModule.forChild(routes),
MatButtonModule,
MatCheckboxModule,
MatDatepickerModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatMenuModule,
MatRippleModule,
MatTableModule,
MatToolbarModule,
MatSelectModule,
MatSnackBarModule,
MatSortModule,
MatTooltipModule,
TranslateModule.forChild(),
MatProgressSpinnerModule,
MatPaginatorModule,
FuseSharedModule,
FuseConfirmDialogModule,
FuseSidebarModule,
FuseDeleteInfoModule
],
providers: [
AsService
]
})
export class AModule {
}
--------------------------------------------------------------------
--BModule
const routes: Routes = [
{
path: '**',
component: BComponent,
resolve: {
contacts: BService
}
},
];
#NgModule({
declarations: [
BComponent
],
imports: [
RouterModule.forChild(routes),
MatButtonModule,
MatCheckboxModule,
MatExpansionModule,
MatDatepickerModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatMenuModule,
MatRippleModule,
MatTableModule,
MatToolbarModule,
MatProgressSpinnerModule,
MatAutocompleteModule,
FuseSharedModule,
MatTabsModule,
FuseConfirmDialogModule,
FuseSidebarModule,
MatSelectModule,
MatSnackBarModule,
MatChipsModule,
MatTableExporterModule,
MatSortModule,
MatTooltipModule,
TranslateModule.forChild(),
MatPaginatorModule,
MatRadioModule,
MatListModule,
MatExpansionModule,
MatSidenavModule,
MatCardModule,
ReactiveFormsModule,
FormsModule,
GalleryModule,
LightboxModule,
],
providers: [
BService,
// {
// provide: HTTP_INTERCEPTORS,
// useClass: CustomInterceptors,
// multi: true
// }
]
})
export class BModule {
}
The Routing for the two lazy loading modules is like below:
{
path: 'A',
loadChildren: './a/a.module#AModule',
canActivate: [AuthGuard],
data: { roles: ['Administrator', 'Supervisor','Operator']}
},
{
path: 'B',
loadChildren: './b/b.module#BModule',
canActivate: [AuthGuard],
data: { roles: ['Administrator']}
}
The problem is that the interceptor is not working for calls made from the BModule but it works successfully for the AModule.
I have found a workaround to this, to add the interceptor in the providers section of the BModule. This isn't right because I am basically instantiating another object of the interceptor in BModule. I want to have the interceptor declared in the app.module to be shared among all lazy loaded modules.
I will appreciate any help or guide to a solution to this problem.
Regards,
Rando.
P.S
Another lazy load module(Lets called C module) that was working, broke down like the B module when someone committed some changes. I ran a git diff to see the differences that made the module stop working. The result is like below:
const routes: Routes = [
## -134,7 +138,10 ## const routes: Routes = [
MatCardModule,
ReactiveFormsModule,
MatListModule,
- FormsModule
+ FormsModule,
+ GalleryModule,
+ LightboxModule,
+ ImageGalleryModule
],
providers: [
CService,
I made some tests, I was able to identify that interceptor will stop working for the module that imports ImageGalleryModule. The following is the ImageGalleryModule:
#NgModule({
declarations: [
ImageGalleryComponent
],
imports: [
MatButtonModule,
MatCheckboxModule,
MatDatepickerModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatMenuModule,
MatRippleModule,
MatTableModule,
MatToolbarModule,
MatTableExporterModule,
MatSnackBarModule,
MatSortModule,
TranslateModule.forChild(),
MatPaginatorModule,
MatTooltipModule,
MatProgressSpinnerModule,
FuseSharedModule,
FuseConfirmDialogModule,
FuseSidebarModule,
MatSelectModule,
MatRadioModule,
MatListModule,
MatExpansionModule,
MatSidenavModule,
MatChipsModule,
MatTabsModule,
MatCardModule,
MatTooltipModule,
MatAutocompleteModule,
FormsModule,
ReactiveFormsModule,
GalleryModule,
LightboxModule,
],
providers: [
DatePipe,
],
exports:[
ImageGalleryComponent
]
})
export class ImageGalleryModule {
}
This is strange that importing this module causes the interceptor to not work since this module does not Import or Export the HttpClientModule.
This is a workaround and not a solution to the problem. So this will not be marked as an accepted answer.
I will start by describing the problem:
HTTP_INTERCEPTOR are reset when lazy-loaded module import HttpClientModule. All interceptors are set up to work on a single instance of the HttpClient service. The moment that the lazy-loaded module imports HttpClientModule, it creates a new instance of HttpClient service. This new instance is injected in all components of the lazy loaded module and every call made from this instance is not intercepted by the interceptor declared in the app-module.
In my case, I searched all around the project and didn't find any import of HttpClientModule except the app module. After hours of debugging, I found out that BModule and CModule imported ImageGalleryModule that was the culprit for these behaviours.
After investigating in ImageGalleryModule, I found out that the modules GalleryModule, LightboxModule imported the HttpClientModule.
When lazy-loaded module imports a module that imports the HttpClientModule, the interceptors are no longer available because a new instance of HttpClient is created for that lazy-loaded module.
WorkAround:
I refactored all my services provided in the app module in a separate module called CoreModule like below:
#NgModule({
imports:[
],
declarations: [
],
providers: [
]
})
export class CoreModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
AuthGuard, Service A, Service B, Service C,
[{ provide: HTTP_INTERCEPTORS, useClass: CustomInterceptors, multi: true }]
],
};
}
}
After that imported CoreModule in app-module and in the lazy-loaded modules like below:
#NgModule({
declarations: [
...
],
imports: [
...
CoreModule.forRoot(),
...
I don't consider this as a solution because we have created a separate interceptor for the lazy-loaded module that import GalleryModule. We have three instances of the interceptor:
The interceptor instantiated in app-module and AModule
The interceptor instantiated in BModule
The interceptor instantiated in CModule
I am developing an Angular library where there is an authentication module that provides an HttpInterceptor. The main idea is to have this interceptor working automatically in any app that imports this authentication module without having to do any extra setup at it.
What I have so far is the following:
AuthenticationModule
#NgModule({
imports: [ConcreteAuthModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: BearerInterceptor,
multi: true
}
]
})
export class AuthenticationModule {
static forRoot(config: AuthConfig): ModuleWithProviders {
return {
ngModule: AuthenticationModule,
providers: [
{
provide: AUTH_CONFIG,
useValue: config
}
]
};
}
}
ConcreteAuthModule
#NgModule({
imports: [ThirdPartyLibModule],
providers: [
{
provide: AuthenticationService,
useClass: ConcreteAuthService
}
]
})
export class ConcreteAuthModule { }
BearerInterceptor
#Injectable()
export class BearerInterceptor implements HttpInterceptor {
constructor(private authService: AuthenticationService) { }
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const headers: any = {};
if (this.authService.isUserAuthenticated()) {
headers.Authorization = `Bearer ${this.singleSignOnService.getUserToken()}`;
}
const authReq = req.clone({ setHeaders: headers });
return next.handle(authReq);
}
}
And from a test Angular app I am importing this module the following way at the AppModule:
#NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
HttpClientModule,
AuthenticationModule.forRoot({ /* config stuff */ })
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
I checked how some third party libraries did this, also came across a couple of Stack Overflow questions that discussed about this and they all suggested having an Angular module created (I already have it: AuthenticationModule), then provide the http-interceptor on it (already have it too) and finally importing this module from an Angular app (also did this).
But still, none of the http requests in my app are being intercepted.
Tried importing the BearerInterceptor directly from my test app and providing it on the AppModule like this:
import { BearerInterceptor } from 'my-lib':
#NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
HttpClientModule,
AuthenticationModule.forRoot({ /* config stuff */ })
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: BearerInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
And that works! But this workaround is not what I am looking for...
You're very close to a working solution.
The key is to look at how the module is being imported by the AppModule.
imports: [
BrowserModule,
HttpClientModule,
AuthenticationModule.forRoot({ /* config stuff */ })
],
That is how the AuthenticationModule is imported by the AppModule, but that NgModule does not provide the HTTP_INTERCEPTORS.
You've provided the token in the #NgModule() decorator, but that module is not being used by your application. It's the module defined by the forRoot() function.
Move the declaration of the HTTP_INTERCEPTORS to the forRoot() function.
Try this instead:
#NgModule({
imports: [ConcreteAuthModule]
})
export class AuthenticationModule {
static forRoot(config: AuthConfig): ModuleWithProviders {
return {
ngModule: AuthenticationModule,
providers: [
{
provide: AUTH_CONFIG,
useValue: config
}, {
provide: HTTP_INTERCEPTORS,
useClass: BearerInterceptor,
multi: true
}
]
};
}
}
The problem was because I was installing the library locally for testing purposes like the following:
$ npm i --save my-lib_path/dist/my-lib
After I published it and installed it from the npm registry it worked fine:
$ npm i --save my-lib
I am trying to add mat-tab correctly into my project,
but it seems like mat tab is not imported properly or something like that. Because not the complete style of the mat-tab seem to be imported
TS code-block
import {Component, Input} from '#angular/core';
#Component({
selector: 'app-code-block',
templateUrl: './code-block.component.html',
styleUrls: ['./code-block.component.scss']
})
export class CodeBlockComponent {
#Input() htmlContent: any;
#Input() scssContent: any;
#Input() typescriptContent: any;
constructor() {
}
}
HTML code-block
<mat-tab-group>
<mat-tab label="HTML">Content 1</mat-tab>
<mat-tab label="SCSS">Content 2</mat-tab>
<mat-tab label="Typescript">Content 3</mat-tab>
</mat-tab-group>
app.module.ts (without the imports above ofc)
#NgModule({
declarations: [
AppComponent,
CodeBlockComponent
],
imports: [
AppRoutingModule,
AppMaterialModule,
BrowserModule,
FlexLayoutModule,
BrowserAnimationsModule,
FormsModule,
],
entryComponents: [],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Result :
Instead of :
Try Import MatTabsModule in your app.module.ts
import {MatTabsModule} from '#angular/material/tabs';
and also add in impports:
imports: [
MatTabsModule
]
Check here : https://stackblitz.com/angular/amaplrmgqnp?file=app%2Ftab-group-basic-example.ts
I am new working with Angular 2 and have a question regarding keeping the code DRY when using multiple modules.
I have a shared module where i import and export common used functionality for other modules.
One of those imports are ng2-translate.
But when I import the SharedModule into a new module, I will need to import and configure the TranslateModule from ng2-translate again, to be able to configure it.
This gives me a pattern i don't like if i should work with multiple modules.
So how would I keep this code DRY and maintain the best practices?
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { TranslateModule } from 'ng2-translate';
#NgModule({
imports: [
CommonModule,
TranslateModule
],
exports: [
CommonModule,
TranslateModule
]
})
export class SharedModule {
}
AppModule
import { NgModule } from '#angular/core';
import { HttpModule, Http } from '#angular/http';
import { TranslateModule, TranslateLoader, TranslateStaticLoader, TranslateService } from 'ng2-translate';
import { SharedModule } from './shared/shared.module';
import { AppComponent } from './app.component';
export function translateLoaderFactory(http: Http) {
return new TranslateStaticLoader(http, '../assets/i18n', '.json')
}
#NgModule({
declarations: [
AppComponent
],
imports: [
HttpModule,
TranslateModule.forRoot({
provide: TranslateLoader,
useFactory: translateLoaderFactory,
deps: [Http]
}),
SharedModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
constructor(translateService: TranslateService) {
translateService.setDefaultLang('en-US');
translateService.use('sv-SE');
}
}
This is my basic structure, if I add a new module I will have to import the SharedModule, TranslateModule and setting the default language using the TranslateService all over again.
How do I prevent this pattern?