244

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
georg-un
  • 1,123
  • 13
  • 24
Tampa
  • 75,446
  • 119
  • 278
  • 425

11 Answers11

633

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)

eko
  • 39,722
  • 10
  • 72
  • 98
  • 101
    Every time I fel like I get my head around NgModule something like this comes up and makes you wonder whether this framework needs to be so complex. At least the error messages helpful though. – daddywoodland Feb 02 '17 at 07:32
  • 3
    What if you already had them in there? why would it say they arent? – Sam Alexander Feb 20 '17 at 18:25
  • 1
    @SamAlexander your question is really broad as you'd appreciate but taking a wild guess; do you use them inside your lazy loaded module? – eko Feb 20 '17 at 18:27
  • thanks, i actually hadnt put it my main module file, just my directory specific one. That part has been fixed – Sam Alexander Feb 20 '17 at 20:23
  • 1
    dialogs in lazy loaded modules do work as of 2.0.0-beta.2 – charlie_pl Mar 13 '17 at 07:52
  • @charlie_pl thanks for the update I put the issue as an example, I'll edit it. – eko Mar 13 '17 at 07:53
  • I am unable to import DialogResultExampleDialog, please tell from which library its to be imported? – Waleed Shahzaib Nov 17 '17 at 07:39
  • 1
    This did not work for me. I added my component in the NgModule entryComponents and I still receive the exact same error. I only have one NgModule at this point, if that helps at all. – kemicofa ghost Feb 14 '18 at 00:11
  • @rottenoats can you reproduce the issue in a plunker or give more info about your architecture please :) – eko Feb 14 '18 at 09:50
  • 1
    Thanks for the note! It's important in my case that works only adding in entryComponents on the app.module – Gere May 04 '18 at 16:01
  • What if I can't put my component (DialogResultExampleDialog) in my app.module (root)? – Michael Jun 13 '18 at 09:16
  • Just found out that MatDialog.open takes a TemplateRef. This can be used as another workaround for lazy loaded modules. – Michael Jun 13 '18 at 09:38
  • my component which calls **ModalComponent** is a grandchild of a component. Neither adding the **ModalComponent** to `entryComponents` nor adding it to `exports` worked for me. **BUT** I can call the **ModalComponent** from some other components which are not grandchilds – canbax Nov 25 '19 at 06:33
53

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]
Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
  • Ugh... I had two dialogs that were otherwise identical but one I had a test route pointing to it. I removed that test route and sure enough... the routing was "helping" me. >:( – Tom Apr 08 '19 at 07:50
  • @Sunil Garg I have another issue. My dialog show but it automatically close within 1sec. Please help me. – Priyanka C Oct 02 '19 at 04:56
11

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<Type<any>|any[]>

Specifies a list of components that should be compiled when this module is defined. For each component listed here, Angular will create a ComponentFactory and store it in the ComponentFactoryResolver.

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
})
georg-un
  • 1,123
  • 13
  • 24
Alireza
  • 100,211
  • 27
  • 269
  • 172
  • 3
    same case with me and will not works: it shows: Error: No component factory found for DialogConfirmComponent. Did you add it to @NgModule.entryComponents? Any idea? – Nam Le Jan 17 '18 at 10:41
  • You need to insert it into ngAfterViewInit (from @angular/core) – Patryk Panek Mar 13 '18 at 07:02
8

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.

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
4

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]
georg-un
  • 1,123
  • 13
  • 24
Yuchao Wu
  • 383
  • 2
  • 8
1

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.

georg-un
  • 1,123
  • 13
  • 24
Menelaos Kotsollaris
  • 5,776
  • 9
  • 54
  • 68
  • you do not face topic-starter issue only till you do not need dynamic created component. If you try (even with primeng) create dialogservice that use dynamic component creation - you will face exactly the same problem... – DicBrus May 23 '18 at 11:28
1

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.

georg-un
  • 1,123
  • 13
  • 24
yuval.bl
  • 4,890
  • 3
  • 17
  • 31
0

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.

LeftOnTheMoon
  • 913
  • 1
  • 7
  • 15
0

In my case, I added my component to declarations and entryComponents and got the same errors. I also needed to add MatDialogModule to imports.

Dela
  • 146
  • 3
  • 15
0

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

MJ X
  • 8,506
  • 12
  • 74
  • 99
0

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

do-ri
  • 7
  • 3