El diálogo de material Angular2 tiene problemas. ¿Lo agregó a @ NgModule.entryComponents?

232

Estoy tratando de seguir los documentos en https://material.angular.io/components/component/dialog pero no puedo entender por qué tiene el siguiente problema.

Agregué lo siguiente en mi componente:

@Component({
  selector: 'dialog-result-example-dialog',
  templateUrl: './dialog-result-example-dialog.html',
})
export class DialogResultExampleDialog {
  constructor(public dialogRef: MdDialogRef<DialogResultExampleDialog>) {}
}

En mi módulo agregué

import { HomeComponent,DialogResultExampleDialog } from './home/home.component';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent,
    HomeComponent,
    DialogResultExampleDialog
  ],

// ...

Sin embargo, recibo este 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
Tampa
fuente

Respuestas:

604

Debe agregar componentes creados dinámicamente entryComponentsdentro de su@NgModule

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent,
    HomeComponent,
    DialogResultExampleDialog        
  ],
  entryComponents: [DialogResultExampleDialog]

Nota: en algunos casos entryComponentsbajo módulos con carga lenta no va a funcionar, como una solución ponerlos en su app.module(raíz)

eko
fuente
99
¡Gracias! Estaba buscando por todas partes esto. En mi caso particular, también necesitaba agregar el componente para que las declarationscosas funcionen
Jasdeep Khalsa, el
95
Cada vez que me gusta, entiendo NgModule, surge algo como esto y te hace preguntarte si este marco debe ser tan complejo. Sin embargo, al menos los mensajes de error son útiles.
daddywoodland
3
¿Y si ya los tuvieras allí? ¿Por qué diría que no lo son?
Sam Alexander
1
@SamAlexander, su pregunta es realmente amplia, como lo agradecería, pero adivinando; ¿los usas dentro de tu módulo cargado perezoso?
eko
1
los diálogos en módulos con carga lenta funcionan desde 2.0.0-beta.2
charlie_pl
53

Necesitas usar entryComponentsdebajo@NgModule .

Esto es para componentes agregados dinámicamente que se agregan usando ViewContainerRef.createComponent() . Agregarlos a entryComponents le dice al compilador de plantillas fuera de línea que los compile y cree fábricas para ellos.

Los componentes registrados en las configuraciones de ruta también se agregan automáticamente entryComponentsporque router-outlettambiénViewContainerRef.createComponent() para agregar componentes enrutados al DOM.

Entonces tu código será como

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent,
    HomeComponent,
    DialogResultExampleDialog        
  ],
  entryComponents: [DialogResultExampleDialog]
Sunil Garg
fuente
Ugh ... Tenía dos cuadros de diálogo que eran idénticos pero uno tenía una ruta de prueba apuntando a él. Eliminé esa ruta de prueba y, efectivamente, la ruta me estaba "ayudando". > :(
Tom
@ Sunil Garg tengo otro problema. Mi cuadro de diálogo se muestra pero se cierra automáticamente en 1 segundo. Por favor, ayúdame.
Priyanka C
10

Esto está sucediendo porque este es un componente dinámico y no lo agregó entryComponentsdebajo @NgModule.

Simplemente agréguelo allí:

@NgModule({
  /* ----------------- */
  entryComponents: [ DialogResultExampleDialog ] // <---- Add it here

Mira cómo habla el equipo de AngularentryComponents :

entryComponents?: Array<Type<any>|any[]>

Especifica una lista de componentes que deben compilarse cuando se define este módulo. Para cada componente enumerado aquí, Angular creará un ComponentFactory y lo almacenará en ComponentFactoryResolver.

Además, esta es la lista de los métodos para @NgModuleincluir entryComponents...

Como puede ver, todos ellos son opcionales (mire los signos de interrogación), incluidos los entryComponentsque aceptan una variedad de componentes:

@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
})
Alireza
fuente
3
mismo caso conmigo y no funciona: muestra: Error: No se encontró fábrica de componentes para DialogConfirmComponent. ¿Lo agregó a @ NgModule.entryComponents? ¿Alguna idea?
Nam Le
Debe insertarlo en ngAfterViewInit (desde @ angular / core)
Patryk Panek
8

Si está intentando usar MatDialogdentro de un servicio, llamemos 'PopupService'y ese servicio se define en un módulo con:

@Injectable({ providedIn: 'root' })

entonces puede que no funcione. Estoy usando carga diferida, pero no estoy seguro de si eso es relevante o no.

Tienes que:

  • Proporcione su PopupServicedirectamente al componente que abre su diálogo - usando [ provide: PopupService ]. Esto le permite usar (con DI) la MatDialoginstancia en el componente. Creo que el componente llamaopen debe estar en el mismo módulo que el componente de diálogo en esta instancia.
  • Mueva el componente de diálogo hacia su app.module (como han dicho algunas otras respuestas)
  • Pase una referencia para matDialogcuando llame a su servicio.

Disculpe mi respuesta confusa, el punto es que es lo providedIn: 'root'que está rompiendo las cosas porque MatDialog necesita recuperar un componente.

Simon_Weaver
fuente
¡esto pasa! de hecho, agregue su servicio para proporcionar en lugar de mirar el componente de entrada, ¡mensaje de error incorrecto!
tibi
Sucediendo lo mismo para mí, pero no pude entender de esta respuesta, ¿qué punto es la solución? ¿O se requieren los 3?
coding_idiot
Tuve el mismo problema
MJVM
4

En caso de carga diferida, solo necesita importar MatDialogModule en el módulo cargado diferido . Entonces, este módulo podrá representar el componente de entrada con su propio MatDialogModule importado :

@NgModule({
  imports:[
    MatDialogModule
  ],
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent,
    HomeComponent,
    DialogResultExampleDialog        
  ],
  entryComponents: [DialogResultExampleDialog]
Yuchao Wu
fuente
1

Si bien es posible integrar el diálogo de material , descubrí que la complejidad de una característica tan trivial es bastante alta. El código se vuelve más complejo si está tratando de lograr características no triviales.

Por esa razón, terminé usando PrimeNG Dialog , que encontré bastante fácil de usar:

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 {}

Simplemente agregue su cuadro de diálogo en el html de su componente:

<m-dialog [isVisible]="true"> </m-dialog>

La documentación de PrimeNG PrimeFaces es fácil de seguir y muy precisa.

Menelaos Kotsollaris
fuente
no enfrenta el problema de inicio de tema solo hasta que no necesite un componente creado dinámicamente. Si intenta (incluso con primeng) crear dialogservice que el uso dinámico de creación de componentes - que se enfrentará a exactamente el mismo problema ...
DicBrus
1

Debe agregarlo entryComponents, como se especifica en los documentos .

@NgModule({
  imports: [
    // ...
  ],
  entryComponents: [
    DialogInvokingComponent, 
    DialogResultExampleDialog
  ],
  declarations: [
    DialogInvokingComponent,   
    DialogResultExampleDialog
  ],
  // ...
})

Aquí hay un ejemplo completo de un archivo de módulo de aplicación con un cuadro de diálogo definido como entryComponents.

yuval.bl
fuente
0

Si eres como yo y estás mirando este hilo pensando "Pero no estoy tratando de agregar un componente, estoy tratando de agregar un protector / servicio / tubería, etc." entonces es probable que haya agregado el tipo incorrecto a una ruta de enrutamiento. Eso es lo que hice. Accidentalmente agregué un protector al componente: sección de una ruta en lugar de canActivate: sección. Me encanta el autocompletado IDE, pero tienes que reducir la velocidad un poco y prestar atención. Si no puede encontrarlo, realice una búsqueda global del nombre del que se queja y observe cada uso para asegurarse de que no se equivocó con un nombre.

LeftOnTheMoon
fuente
0

En mi caso, agregué mi componente a declaraciones y entryComponents y obtuve los mismos errores. También necesitaba agregar MatDialogModule a las importaciones.

Dela
fuente
0

Si alguien necesita llamar a Dialog desde los servicios, aquí está cómo resolver el problema. Estoy de acuerdo con algunas de las respuestas anteriores, mi respuesta es para llamar al diálogo en los servicios si alguien puede tener problemas.

Cree un servicio, por ejemplo, DialogService, luego mueva su función de diálogo dentro de los servicios y agregue su servicio de diálogo en el componente que llame como el siguiente código:

 @Component({
  selector: "app-newsfeed",
  templateUrl: "./abc.component.html",
  styleUrls: ["./abc.component.css",],
  providers:[DialogService]
})

de lo contrario obtienes un error

MJVM
fuente