A caixa de diálogo do material Angular2 apresenta problemas - Você a adicionou a @ NgModule.entryComponents?

232

Estou tentando seguir os documentos em https://material.angular.io/components/component/dialog, mas não consigo entender por que ele tem o problema abaixo?

Eu adicionei o seguinte no meu componente:

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

No meu módulo eu adicionei

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

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

// ...

No entanto, recebo esse erro ....

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
fonte

Respostas:

604

Você precisa adicionar componentes criados dinamicamente para entryComponentsdentro do seu@NgModule

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

Nota: Em alguns casos, entryComponentsnos módulos carregados preguiçosamente , não funcionará, pois uma solução alternativa os coloca no seu app.module(root)

eko
fonte
9
Obrigado! Estava procurando em todos os lugares por isso. No meu caso particular, eu também precisava para adicionar o componente ao declarationsfazer as coisas para o trabalho
Jasdeep Khalsa
95
Toda vez que eu penso no NgModule, surge algo assim e faz você pensar se essa estrutura precisa ser tão complexa. Pelo menos as mensagens de erro são úteis.
22417 daddywoodland
3
E se você já os tivesse lá? por que diria que eles não estão?
Sam Alexander
1
@ SamAlexander, sua pergunta é realmente ampla, como você gostaria, mas adivinhando; você os usa dentro do seu módulo carregado preguiçosamente?
Eko
1
diálogos em módulos carregados preguiçoso fazer o trabalho a partir de 2.0.0-beta.2
charlie_pl
53

Você precisa usar entryComponentsem @NgModule.

Isto é para componentes adicionados dinamicamente que são adicionados usando ViewContainerRef.createComponent(). Adicioná-los a entryComponents informa ao compilador de modelos offline para compilá-los e criar fábricas para eles.

Os componentes registrados nas configurações de rota também são adicionados automaticamente entryComponentsporque router-outlettambém são usados ViewContainerRef.createComponent()para adicionar componentes roteados ao DOM.

Então, seu código será como

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent,
    HomeComponent,
    DialogResultExampleDialog        
  ],
  entryComponents: [DialogResultExampleDialog]
Sunil Garg
fonte
Ugh ... eu tinha duas caixas de diálogo idênticas, mas uma tinha uma rota de teste apontando para ela. Eu removi a rota de teste e com certeza ... o roteamento estava "me ajudando". > :(
Tom
@ Sunil Garg Eu tenho outro problema. Minha caixa de diálogo é exibida, mas fecha automaticamente em 1 segundo. Por favor me ajude.
Priyanka C
10

Isso está acontecendo porque este é um componente dinâmico e você não o adicionou ao entryComponentssub @NgModule.

Basta adicioná-lo lá:

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

Veja como a equipe Angular fala sobre entryComponents:

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

Especifica uma lista de componentes que devem ser compilados quando este módulo é definido. Para cada componente listado aqui, o Angular criará um ComponentFactory e o armazenará no ComponentFactoryResolver.

Além disso, esta é a lista dos métodos para @NgModuleincluir entryComponents...

Como você pode ver, todos eles são opcionais (veja os pontos de interrogação), incluindo os entryComponentsque aceitam uma matriz 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
fonte
3
mesmo caso comigo e não funciona: mostra: Erro: Nenhuma fábrica de componentes encontrada para DialogConfirmComponent. Você o adicionou a @ NgModule.entryComponents? Qualquer ideia?
Nam Le
Você precisa inseri-lo em ngAfterViewInit (de @ / core angular)
Patryk Panek
8

Se você estiver tentando usar MatDialogdentro de um serviço - vamos chamá-lo 'PopupService'e esse serviço é definido em um módulo com:

@Injectable({ providedIn: 'root' })

então pode não funcionar. Estou usando carregamento lento, mas não tenho certeza se isso é relevante ou não.

Voce tem que:

  • Forneça seu PopupServicediretamente ao componente que abre sua caixa de diálogo - usando [ provide: PopupService ]. Isso permite usar (com DI) a MatDialoginstância no componente. Eu acho que a chamada de componente openprecisa estar no mesmo módulo que o componente de diálogo nesta instância.
  • Mova o componente de diálogo para o seu app.module (como algumas outras respostas disseram)
  • Passe uma referência para matDialogquando você ligar para o seu serviço.

Desculpe minha resposta confusa, o ponto é que é isso providedIn: 'root'que está quebrando as coisas, porque o MatDialog precisa retroceder um componente.

Simon_Weaver
fonte
isto acontece! adicione seu serviço para fornecer, em vez de olhar para o componente de entrada, a mensagem de erro errada!
tibi
Acontecendo o mesmo para mim, mas não consegui entender com esta resposta, qual é a solução? Ou todos os 3 são obrigatórios?
Codigo_idiot 20/08/19
Eu tive o mesmo problema
MJVM
4

No caso de carregamento lento, você só precisa importar o MatDialogModule no módulo carregado lento. Então este módulo poderá renderizar o componente de entrada com seu próprio MatDialogModule importado :

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

Embora a integração do diálogo de material seja possível , descobri que a complexidade de um recurso tão trivial é bastante alta. O código fica mais complexo se você estiver tentando obter recursos não triviais.

Por esse motivo, acabei usando o PrimeNG Dialog , que achei bastante simples 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 {}

Basta adicionar sua caixa de diálogo ao html do seu componente:

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

A documentação do PrimeNG PrimeFaces é fácil de seguir e muito precisa.

Menelaos Kotsollaris
fonte
você não enfrenta problemas do iniciador de tópicos apenas até não precisar do componente criado dinâmico. Se você tentar (mesmo com primeng) criar dialogservice que a criação componente uso dinâmico - você vai enfrentar exatamente o mesmo problema ...
DicBrus
1

Você deve adicioná-lo entryComponents, conforme especificado nos documentos .

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

Aqui está um exemplo completo de um arquivo de módulo de aplicativo com uma caixa de diálogo definida como entryComponents.

yuval.bl
fonte
0

Se você é como eu, e está olhando para este tópico pensando "Mas não estou tentando adicionar um componente, estou tentando adicionar um protetor / serviço / tubo, etc." é provável que o problema tenha sido adicionado ao tipo de caminho errado. Foi o que eu fiz. Eu acidentalmente adicionei uma proteção à seção component: de um caminho em vez da seção canActivate:. Eu amo o preenchimento automático do IDE, mas você precisa desacelerar um pouco e prestar atenção. Se você não conseguir encontrá-lo, faça uma pesquisa global pelo nome do qual está reclamando e verifique todos os usos para garantir que você não tenha escolhido um nome.

LeftOnTheMoon
fonte
0

No meu caso, adicionei meu componente a declarações e entryComponents e obtive os mesmos erros. Eu também precisava adicionar MatDialogModule às importações.

Dela
fonte
0

Se alguém precisar chamar a Dialog de serviços, aqui está como resolver o problema. Concordo com algumas das respostas acima, minha resposta é para chamar a caixa de diálogo nos serviços se alguém tiver problemas.

Crie um serviço, por exemplo, DialogService, mova sua função de diálogo dentro dos serviços e adicione seu serviço de diálogo no componente que você chama, como no código abaixo:

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

caso contrário, você receberá um erro

MJVM
fonte