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
Related
i am porting over and angular 6 app to angular 13 and i am having trouble with pipes. the app wont compile.
i have a custom pipe on a component that the compiler says doesnt exist
Property 'shortDate' does not exist on type 'TransactionsComponent'.
code is as follows (and works in old version of angular)
angular pipe:
import { PipeTransform, Pipe } from '#angular/core';
import { DatePipe } from '#angular/common';
#Pipe({
name: 'shortDate'
})
export class DateFormatPipe extends DatePipe implements PipeTransform {
override transform(value: any, args?: any): any {
///MMM/dd/yyyy
return super.transform(value, "MM/dd/yyyy");
}
}
html
<div class="dt">{{transaction.transactionDate | date: shortDate}}</div>
Shared Module
#NgModule({
declarations: [
DateFormatPipe
],
imports: [
AppRoutingModule,
BrowserModule,
FormsModule,
HttpClientModule,
HttpInterceptorModule,
ReactiveFormsModule,
],
exports: [
AppRoutingModule,
BrowserModule,
FormsModule,
HttpClientModule,
HttpInterceptorModule,
ReactiveFormsModule ,
],
})
export class SharedModule {
static forRoot(): ModuleWithProviders<SharedModule> {
return {
ngModule: SharedModule,
providers:
[
DateFormatPipe,
]
};
}
}
consuming module
#NgModule({
declarations: [
],
imports: [
SharedModule
],
providers: [
],
})
export class TransactionModule{ }
in app.module
imports: [
SharedModule.forRoot(),
TransactionModule
] ,
please note: I have also tried to put the pipe in the exports section of shared module. that doesnt work either. i'm sure im just missing something silly. does anyone have any ideas?
Try this
<div class="dt">{{transaction.transactionDate | shortDate}}</div>
Try adding standalone: true flag to the Pipe decorator
#Pipe({
name: 'shortDate',
standalone: true
})
So I want to add machine detail and buton bar to my app, and this is what happens. I've used it in other parts aswell and it worked fine, only in core module are the errors.
The error message
main.ts
import { enableProdMode } from '#angular/core';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
core module (error appears when I add "IfaButtonModule" or "MachineModule")
#NgModule({
declarations: [
TakePhotoComponent,
ConfirmationDialogComponent,
ShareMachineComponent,
NotificationsComponent,
],
imports: [
CommonModule,
WebcamModule,
MatButtonModule,
TranslateModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
ReactiveFormsModule,
MatIconModule,
MatExpansionModule,
MatBadgeModule,
MatCardModule,
MatMenuModule,
IfaButtonModule,
MachineModule
],
exports: [
TakePhotoComponent,
ConfirmationDialogComponent,
ShareMachineComponent,
NotificationsComponent
],
providers: [NgxImageCompressService]
})
export class CoreModule { }
button-module
#NgModule({
declarations: [
IfaButtonBarItemComponent,
IfaButtonBarComponent,
IfaButtonBarGroupComponent
],
imports: [
CommonModule,
CoreModule,
MatButtonModule,
TranslateModule
],
exports: [
IfaButtonBarComponent,
IfaButtonBarGroupComponent,
IfaButtonBarItemComponent
]
})
export class IfaButtonModule { }
machine module
#NgModule({
declarations: [
MachineListComponent,
MachineDetailEditComponent,
MachineDetailComponent,
MachineListItemComponent
],
imports: [
CommonModule,
CoreModule,
MatCardModule,
MatMenuModule,
MatListModule,
MatButtonModule,
FormsModule,
ReactiveFormsModule,
NgxPaginationModule,
MatFormFieldModule,
MatInputModule,
TranslateModule,
MatDialogModule,
MatExpansionModule,
IfaButtonModule,
OperationModeModule,
ProtectionModule,
ManipulationModule
],
exports: [
MatMenuModule,
MachineDetailEditComponent,
MachineListComponent,
MachineDetailComponent
]
})
export class MachineModule {
}
the html that uses the components: (inside the core module area)
<ng-container>
<app-machine-detail [machine]="completeMachine">
</app-machine-detail>
<app-ifa-button-bar-group>
<app-ifa-button-bar-item [label]="'MISC.BACK'" (click)="navigateBack()">
</app-ifa-button-bar-item>
</app-ifa-button-bar-group>
</ng-container>
This is probably happening because you import CoreModule in the MachineModule and the MachineModule in the CoreModule. This should not happen, you should re-work your module dependencies and fix the circular import. IfaButtonModule has the exact same issue.
after installing Ngx Google Analytics module from NPM, I have implemented it in my app module, for auto tracking I have imported two modules, NgxGoogleAnalyticsModule and NgxGoogleAnalyticsRouterModule, and I got this error:
import { BrowserModule } from "#angular/platform-browser";
import { NgModule } from "#angular/core";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { SharedModule } from "./shared/shared.module";
import { HttpClientModule } from "#angular/common/http";
import {
NgxGoogleAnalyticsModule,
NgxGoogleAnalyticsRouterModule,
} from "ngx-google-analytics";
const pages = [];
#NgModule({
declarations: [AppComponent, pages],
imports: [
AppRoutingModule,
BrowserModule,
HttpClientModule,
SharedModule,
ReactiveFormsModule,
BrowserAnimationsModule,
NgxGoogleAnalyticsModule.forRoot(environment.ga),
NgxGoogleAnalyticsRouterModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
Error after ng serve in the console:
My Solution
I was trying to solve it and I have fixed it this way:
in providers, I have added this service >>> GoogleAnalyticsService
#NgModule({
declarations: [AppComponent, pages],
imports: [
AppRoutingModule,
BrowserModule,
HttpClientModule,
SharedModule,
ReactiveFormsModule,
BrowserAnimationsModule,
NgxGoogleAnalyticsModule.forRoot(environment.ga),
NgxGoogleAnalyticsRouterModule
],
providers: [
GoogleAnalyticsService
],
bootstrap: [AppComponent],
})
export class AppModule {}
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 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