i have this config for my site :
import { InjectionToken } from '#angular/core';
import { HttpHeaders } from '#angular/common/http';
export let APP_CONFIG = new InjectionToken<IAppConfig>('app.config');
export interface IAppConfig {
apiEndpoint: string;
headersOptions: HttpHeaders;
}
export const AppConfig: IAppConfig = {
apiEndpoint: 'https://localhost:44354/',
headersOptions : new HttpHeaders({ 'Content-Type': 'application/json' }),
};
and i need use the core.module for using the config :
#NgModule({
declarations: [],
imports: [
CommonModule,
ToastrModule.forRoot()
],
exports: [],
providers: [
{
provide: APP_CONFIG,
useValue: AppConfig,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: RequestInterceptor, multi: true
}
],
})
export class CoreModule {
constructor( #Optional() #SkipSelf() core: CoreModule) {
if (core) {
throw new Error("CoreModule should be imported ONLY in AppModule.");
}
}
}
i using the core.module in app.module .
this my app.module :
#NgModule({
declarations: [
AppComponent,
TopHeaderComponent
],
imports: [
BrowserModule,
HttpClientModule,
SharedModule,
ReactiveFormsModule,
AppRoutingModule,
ToastrModule.forRoot(),
BrowserAnimationsModule,
FormsModule,
CoreModule,
NgZorroAntdModule
],
providers:[{ provide: NZ_I18N, useValue: en_US }],
bootstrap: [AppComponent]
})
export class AppModule { }
now i need to use the AppConfig in my service :
constructor(httpClient: HttpClient, #Inject(APP_CONFIG) private appConfig: IAppConfig) {
super(httpClient);
}
but it show me this error :
Uncaught (in promise): NullInjectorError: StaticInjectorError(AppModule)[[object Object]]:
whats the problem ? how can i solve this problem???
Modify your core module like the following (Remove multi: true)
#NgModule({
declarations: [],
imports: [
CommonModule,
ToastrModule.forRoot()
],
exports: [],
providers: [
{
provide: APP_CONFIG,
useValue: AppConfig //multi: true -> Remove here
},
{
provide: HTTP_INTERCEPTORS,
useClass: RequestInterceptor,
multi: true
}
],
})
export class CoreModule {
constructor( #Optional() #SkipSelf() core: CoreModule) {
if (core) {
throw new Error("CoreModule should be imported ONLY in AppModule.");
}
}
}
Then you can inject in your service as below:
#Injectable()
export class MainService {
constructor(#Inject(APP_CONFIG) private appConfig: IAppConfig) { }
getEndPoint(): string {
alert(this.appConfig.apiEndpoint);
return this.appConfig.apiEndpoint;
}
}
Stackblitz Here
Related
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 am getting this error while while doing npm run serve:ssr
my app.module.ts looks like this:
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
HttpClientModule,
AppRoutingModule,
],
providers: [ProductService,
{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true}
],
bootstrap: [AppComponent]
})
export class AppModule { }
My home.component.ts looks like this:
constructor(private productService: ProductService) { }
ngOnInit(): void {
this.productService.getHomeData().subscribe(
(data) => {
console.log(data);
},
(error) => {
console.log(error);
}
);
}
my product.service looks like this:
#Injectable()
export class ProductService {
getHomeData(): Observable<any> {
return "this.data";
}
}
Kindly help me fix this issue
ERROR TypeError: this.productService.getHomeData is not a function
at HomeComponent.ngOnInit
Hi I have a service for the Angular material dialog, like this:
export class DialogModelService {
participant: ParticipantInfoDTO;
constructor(private dialog: MatDialog, route: ActivatedRoute) {
this.participant = route.snapshot.data['participant'];
}
openEcheqSelectorDialog(): Observable<any> {
const dialogRef = this.dialog.open(EcheqSelectorComponent, {
width: '600px',
maxHeight: 'calc(100vh - 2em)',
data: {
participant: console.log('participantIDTest', this.participant)
}
});
return dialogRef.afterClosed();
}
}
And now I try it to inject in a component like this:
export class DetailComponent implements OnInit {
#Input() participant: ParticipantInfoDTO;
constructor(private dialog: MatDialog, route: ActivatedRoute, private dialogModelService: DialogModelService) {
this.participant = route.snapshot.data['participant'];
}
ngOnInit() {
}
openEcheqSelectorDialog(){
this.dialogModelService.openEcheqSelectorDialog().subscribe(data => console.log(data));
}
}
and this is the template:
<button mat-raised-button class="button-spacing" (click)="openEcheqSelectorDialog()" i18n>Send echeq</button>
And I have the component declard in this module:
#NgModule({
declarations: [ListComponent, DetailComponent, ExtendedSearchComponent, LoaderComponent, ChangeEmailComponent],
exports: [LoaderComponent, DetailComponent],
export class ParticipantModule {}
But I get this error:
DetailComponent.html:9 ERROR Error: No component factory found for EcheqSelectorComponent. Did you add it to #NgModule.entryComponents?
at noComponentFactoryError (core.js:7754)
at CodegenComponentFactoryResolver.push../node_modules/#angular/core/fesm5/core.js.CodegenComponentFactoryResolver.resolveComponentFactory (core.js:7792)
at CdkPortalOutlet.push../node_modules/#angular/cdk/esm5/portal.es5.js.CdkPortalOutlet.attachComponentPortal (portal.es5.js:654)
at
So my question is: what I have to change?
Thank you
I have that. I have put them both in the module:
#NgModule({
declarations: [
EcheqQuestionComponent,
EcheqDisplayComponent,
EcheqViewListComponent,
EcheqViewItemComponent,
EcheqSelectorComponent,
MetaBoxComponent,
ConfirmDialogComponent,
StrenumQuestionComponent,
StrlistQuestionComponent,
RadioQuestionComponent
],
exports:[
EcheqSelectorComponent
],
imports: [
// Angular
CommonModule,
FormsModule,
// Angular Material
MatDialogModule,
MatButtonModule,
MatIconModule,
MatInputModule,
MatSortModule,
MatPaginatorModule,
MatTableModule,
MatExpansionModule,
MatCardModule,
MatDividerModule,
MatCheckboxModule,
MatRadioModule,
MatSelectModule,
// Carapax
AuthModule,
ParticipantEcheqRoutingModule,
SharedModule
],
entryComponents: [
EcheqSelectorComponent,
ConfirmDialogComponent
]
})
export class ParticipantEcheqModule { }
I think the issue is related where DialogModelService is provided.
To check if that is the issue, try providing the DialogModelService in the ParticipantEcheqModule:
#NgModule({
declarations: [
EcheqQuestionComponent,
EcheqDisplayComponent,
EcheqViewListComponent,
EcheqViewItemComponent,
EcheqSelectorComponent,
MetaBoxComponent,
ConfirmDialogComponent,
StrenumQuestionComponent,
StrlistQuestionComponent,
RadioQuestionComponent
],
exports:[
EcheqSelectorComponent
],
providers: [
DialogModelService
],
imports: [
// Angular
CommonModule,
FormsModule,
// Angular Material
MatDialogModule,
MatButtonModule,
MatIconModule,
MatInputModule,
MatSortModule,
MatPaginatorModule,
MatTableModule,
MatExpansionModule,
MatCardModule,
MatDividerModule,
MatCheckboxModule,
MatRadioModule,
MatSelectModule,
// Carapax
AuthModule,
ParticipantEcheqRoutingModule,
SharedModule
],
entryComponents: [
EcheqSelectorComponent,
ConfirmDialogComponent
]
})
export class ParticipantEcheqModule { }
Try adding EcheqSelectorComponent inside module's entryComponents and declarations
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 have this in a service- I18nProviderService:
createTranslationProviders(response) {
const locale = 'de';
let translationProvider: any;
translationProvider = [{
provide: TRANSLATIONS,
useValue: response
},
{
provide: TRANSLATIONS_FORMAT,
useValue: 'xlf'
},
{
provide: LOCALE_ID,
useValue: locale
}
];
return translationProvider;
}
getTranslationProvider() {
this.getTranslationFile()
.subscribe(
(response: Response) => this.createTranslationProviders(response),
(error) => console.log(error)
);
}
and this in my app.module.ts
export function startupServiceFactory(myService: I18nProviderService): Function {
return () => myService.getTranslationProvider();
}
#NgModule({
declarations: [
],
imports: [
BrowserModule,
ReactiveFormsModule,
HttpModule,
NguiAutoCompleteModule
],
providers: [I18nProviderService,
{
provide: APP_INITIALIZER,
useFactory: (myService: I18nProviderService) => () => myService.getTranslationProvider(),
deps: [I18nProviderService],
multi: true
},
],
bootstrap: [AppComponent]
})
export class AppModule {}
Why is the TRANSLATIONS_FORMAT, LOCALE_ID and TRANSLATIONS not mapped correctly. Means, if I trace the LOCALE_ID in my app.component.ts it has the default value.. not "de". I like to load my xlf translation file before app is init.