I am trying to follow the docs on https://material.angular.io/components/component/dialog but I cannot understand why it has the below issue?
I added the below on my component:
@Component({
selector: 'dialog-result-example-dialog',
templateUrl: './dialog-result-example-dialog.html',
})
export class DialogResultExampleDialog {
constructor(public dialogRef: MdDialogRef<DialogResultExampleDialog>) {}
}
In my module I added
import { HomeComponent,DialogResultExampleDialog } from './home/home.component';
@NgModule({
declarations: [
AppComponent,
LoginComponent,
DashboardComponent,
HomeComponent,
DialogResultExampleDialog
],
// ...
Yet I get this error....
EXCEPTION: Error in ./HomeComponent class HomeComponent - inline template:53:0 caused by: No component factory found for DialogResultExampleDialog. Did you add it to @NgModule.entryComponents?
ErrorHandler.handleError @ error_handler.js:50
next @ application_ref.js:346
schedulerFn @ async.js:91
SafeSubscriber.__tryOrUnsub @ Subscriber.js:223
SafeSubscriber.next @ Subscriber.js:172
Subscriber._next @ Subscriber.js:125
Subscriber.next @ Subscriber.js:89
Subject.next @ Subject.js:55
EventEmitter.emit @ async.js:77
NgZone.triggerError @ ng_zone.js:329
onHandleError @ ng_zone.js:290
ZoneDelegate.handleError @ zone.js:246
Zone.runTask @ zone.js:154
ZoneTask.invoke @ zone.js:345
error_handler.js:52 ORIGINAL EXCEPTION: No component factory found for DialogResultExampleDialog. Did you add it to @NgModule.entryComponents?
ErrorHandler.handleError @ error_handler.js:52
next @ application_ref.js:346
schedulerFn @ async.js:91
SafeSubscriber.__tryOrUnsub @ Subscriber.js:223
SafeSubscriber.next @ Subscriber.js:172
Subscriber._next @ Subscriber.js:125
Subscriber.next @ Subscriber.js:89
Subject.next @ Subject.js:55
EventEmitter.emit @ async.js:77
NgZone.triggerError @ ng_zone.js:329
onHandleError @ ng_zone.js:290
ZoneDelegate.handleError @ zone.js:246
Zone.runTask @ zone.js:154
ZoneTask.invoke @ zone.js:345
Angular 9.0.0 <
Since 9.0.0 with Ivy, the entryComponents property is no longer necessary. See deprecations guide.
Angular 9.0.0 >
You need to add dynamically created components to entryComponents
inside your @NgModule
@NgModule({
declarations: [
AppComponent,
LoginComponent,
DashboardComponent,
HomeComponent,
DialogResultExampleDialog
],
entryComponents: [DialogResultExampleDialog]
Note: In some cases entryComponents
under lazy loaded modules will not work, as a workaround put them in your app.module
(root)
You need to use entryComponents
under @NgModule
.
This is for dynamically added components that are added using ViewContainerRef.createComponent()
. Adding them to entryComponents tells the offline template compiler to compile them and create factories for them.
The components registered in route configurations are added automatically to entryComponents
as well because router-outlet
also uses ViewContainerRef.createComponent()
to add routed components to the DOM.
So your code will be like
@NgModule({
declarations: [
AppComponent,
LoginComponent,
DashboardComponent,
HomeComponent,
DialogResultExampleDialog
],
entryComponents: [DialogResultExampleDialog]
This is happening because this is a dynamic component and you didn't add it to entryComponents
under @NgModule
.
Simply add it there:
@NgModule({
/* ----------------- */
entryComponents: [ DialogResultExampleDialog ] // <---- Add it here
Look at how the Angular team talks about entryComponents
:
entryComponents?: Array
Also, this is the list of the methods on @NgModule
including entryComponents
...
As you can see, all of them are optional (look at the question marks), including entryComponents
which accept an array of components:
@NgModule({
providers?: Provider[]
declarations?: Array<Type<any>|any[]>
imports?: Array<Type<any>|ModuleWithProviders|any[]>
exports?: Array<Type<any>|any[]>
entryComponents?: Array<Type<any>|any[]>
bootstrap?: Array<Type<any>|any[]>
schemas?: Array<SchemaMetadata|any[]>
id?: string
})
If you're trying to use MatDialog
inside a service - let's call it 'PopupService'
and that service is defined in a module with:
@Injectable({ providedIn: 'root' })
then it may not work. I am using lazy loading, but not sure if that's relevant or not.
You have to:
Provide your PopupService directly to the component that opens your dialog - using [ provide: PopupService ]. This allows it to use (with DI) the MatDialog instance in the component. I think the component calling open needs to be in the same module as the dialog component in this instance.
Move the dialog component up to your app.module (as some other answers have said)
Pass a reference for matDialog when you call your service.
Excuse my jumbled answer, the point being it's the providedIn: 'root'
that is breaking things because MatDialog needs to piggy-back off a component.
In case of lazy loading, you just need to import MatDialogModule in lazy loaded module. Then this module will be able to render entry component with its own imported MatDialogModule:
@NgModule({
imports:[
MatDialogModule
],
declarations: [
AppComponent,
LoginComponent,
DashboardComponent,
HomeComponent,
DialogResultExampleDialog
],
entryComponents: [DialogResultExampleDialog]
While integrating material dialog is possible, I found that the complexity for such a trivial feature is pretty high. The code gets more complex if you are trying to achieve a non-trivial features.
For that reason, I ended up using PrimeNG Dialog, which I found pretty straightforward to use:
m-dialog.component.html
:
<p-dialog header="Title">
Content
</p-dialog>
m-dialog.component.ts
:
@Component({
selector: 'm-dialog',
templateUrl: 'm-dialog.component.html',
styleUrls: ['./m-dialog.component.css']
})
export class MDialogComponent {
// dialog logic here
}
m-dialog.module.ts
:
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { DialogModule } from "primeng/primeng";
import { FormsModule } from "@angular/forms";
@NgModule({
imports: [
CommonModule,
FormsModule,
DialogModule
],
exports: [
MDialogComponent,
],
declarations: [
MDialogComponent
]
})
export class MDialogModule {}
Simply add your dialog into your component's html:
<m-dialog [isVisible]="true"> </m-dialog>
PrimeNG PrimeFaces documentation is easy to follow and very precise.
You must add it to entryComponents
, as specified in the docs.
@NgModule({
imports: [
// ...
],
entryComponents: [
DialogInvokingComponent,
DialogResultExampleDialog
],
declarations: [
DialogInvokingComponent,
DialogResultExampleDialog
],
// ...
})
Here is a full example for an app module file with a dialog defined as entryComponents
.
If you are like me, and are staring at this thread thinking "But I'm not trying to add a component, I am trying to add a guard/service/pipe, etc." then the issue is likely that you have added the wrong type to a routing path. That is what I did. I accidentally added a guard to the component: section of a path instead of the canActivate: section. I love IDE autocomplete but you have to slow down a bit and pay attention. If you absolutely can't find it, do a global search for the name it is complaining about and look at every usage to make sure you didn't slip-up with a name.
In my case, I added my component to declarations and entryComponents and got the same errors. I also needed to add MatDialogModule to imports.
If someone needs to call Dialog from services here is how to solve the issue. I agree with some of above answer, my answer is for calling dialog in services if someone may face issues on.
Create a service for example DialogService then move your dialog function inside the services and add your dialogservice in the component you call like below code:
@Component({
selector: "app-newsfeed",
templateUrl: "./abc.component.html",
styleUrls: ["./abc.component.css",],
providers:[DialogService]
})
otherwise you get error
I had the same issues and i had dialogComponent in EntryComponents and it still did not work. this is how I was able to solve the problem. the link is here to a previously answered post:
https://stackoverflow.com/a/64224799/14385758
Success story sharing
declarations
to get things to work