W oknie dialogowym materiału Angular2 występują problemy - Czy dodałeś go do @ NgModule.entryComponents?

232

Próbuję postępować zgodnie z dokumentami na https://material.angular.io/components/component/dialog, ale nie rozumiem, dlaczego występuje poniższy problem?

Dodałem poniżej do mojego komponentu:

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

W moim module dodałem

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

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

// ...

Jednak dostaję ten błąd ....

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
źródło

Odpowiedzi:

604

Musisz dodać dynamicznie tworzone komponenty do entryComponentsswojego@NgModule

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

Uwaga: W niektórych przypadkach entryComponentswynikających leniwych załadowanych modułów nie będzie działać, jako obejście umieścić je w swoim app.module(root)

eko
źródło
9
Dzięki! Szukałem wszędzie tego. W moim szczególnym przypadku musiałem również dodać komponent, aby declarationswszystko działało
Jasdeep Khalsa
95
Za każdym razem, gdy czuję się tak, jakbym kręciła się wokół NgModule, pojawia się coś takiego i sprawia, że ​​zastanawiasz się, czy ten framework musi być tak złożony. Przynajmniej pomocne są komunikaty o błędach.
daddywoodland
3
Co jeśli już je tam miałeś? dlaczego miałoby to powiedzieć, że nie są?
Sam Alexander
1
@SamAlexander twoje pytanie jest bardzo szerokie, jeśli docenisz to, ale zgadywasz; używasz ich w swoim leniwie załadowanym module?
eko
1
dialogi w leniwe załadowanych modułów działają zgodnie z 2.0.0-beta.2
charlie_pl
53

Musisz użyć entryComponentspod @NgModule.

Dotyczy to składników dodawanych dynamicznie, które są dodawane za pomocą ViewContainerRef.createComponent(). Dodanie ich do entryComponents każe kompilatorowi szablonów offline skompilować je i utworzyć dla nich fabryki.

Komponenty zarejestrowane w konfiguracjach tras również są dodawane automatycznie, entryComponentsponieważ router-outletrównież służą ViewContainerRef.createComponent()do dodawania komponentów trasowanych do DOM.

Twój kod będzie podobny

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent,
    HomeComponent,
    DialogResultExampleDialog        
  ],
  entryComponents: [DialogResultExampleDialog]
Sunil Garg
źródło
Ugh ... Miałem dwa dialogi, które byłyby identyczne, ale jeden miałem do niego trasę testową. Usunąłem tę trasę testową i na pewno ... routing mi „pomógł”. > :(
Tom
@Sunil Garg Mam inny problem. Moje okno dialogowe pokazuje się, ale automatycznie zamyka się w ciągu 1 sekundy. Proszę pomóż mi.
Priyanka C
10

Dzieje się tak, ponieważ jest to element dynamiczny i nie dodałeś go do entryComponentsunder @NgModule.

Po prostu dodaj go tam:

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

Zobacz, jak mówi zespół AngularentryComponents :

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

Określa listę komponentów, które powinny zostać skompilowane, gdy ten moduł jest zdefiniowany. Dla każdego wymienionego tutaj składnika Angular utworzy ComponentFactory i zapisze go w ComponentFactoryResolver.

Jest to także lista metod @NgModuleobejmujących entryComponents...

Jak widać, wszystkie z nich są opcjonalne (spójrz na znaki zapytania), w tym entryComponentsakceptują szereg komponentów:

@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
źródło
3
ta sama sprawa ze mną i nie działa: pokazuje: Błąd: Nie znaleziono fabryki komponentów dla DialogConfirmComponent. Czy dodałeś go do @ NgModule.entryComponents? Dowolny pomysł?
Nam Le
Musisz wstawić go do ngAfterViewInit (z @ angular / core)
Patryk Panek
8

Jeśli próbujesz użyć MatDialogwewnątrz usługi - nazwijmy ją, 'PopupService'a ta usługa jest zdefiniowana w module z:

@Injectable({ providedIn: 'root' })

to może nie działać. Używam leniwego ładowania, ale nie jestem pewien, czy to jest istotne, czy nie.

Musisz:

  • Podaj PopupServicebezpośrednio komponentowi, który otwiera okno dialogowe - za pomocą [ provide: PopupService ]. Pozwala to na użycie (z DI) MatDialoginstancji w komponencie. Myślę, że w tym przypadku wywołanie komponentu openmusi znajdować się w tym samym module co komponent okna dialogowego.
  • Przenieś komponent okna dialogowego w górę do swojego modułu app.module (jak powiedzieli niektóre inne odpowiedzi)
  • Przekaż referencję, matDialogkiedy zadzwonisz do serwisu.

Przepraszam, moja pomieszana odpowiedź, chodzi o to, providedIn: 'root'że to psuje rzeczy, ponieważ MatDialog musi odeprzeć komponent.

Simon_Weaver
źródło
to się stało! rzeczywiście dodaj swoją usługę, aby zamiast patrzeć na entrycomponent, zły komunikat o błędzie!
tibi
Dzieje się tak samo dla mnie, ale nie mogłem zrozumieć z tej odpowiedzi, który punkt jest rozwiązaniem? Czy wszystkie 3 są wymagane?
coding_idiot
Miałem ten sam problem
MJVM
4

W przypadku leniwego ładowania wystarczy zaimportować MatDialogModule do modułu leniwie ładowanego. Następnie ten moduł będzie mógł renderować komponent wejścia z własnym importowanym MatDialogModule :

@NgModule({
  imports:[
    MatDialogModule
  ],
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent,
    HomeComponent,
    DialogResultExampleDialog        
  ],
  entryComponents: [DialogResultExampleDialog]
Yuchao Wu
źródło
1

Chociaż integracja dialogów materiałowych jest możliwa , stwierdziłem, że złożoność tak trywialnej funkcji jest dość wysoka. Kod staje się bardziej złożony, jeśli próbujesz uzyskać nietrywialne funkcje.

Z tego powodu korzystałem z PrimeNG Dialog , co było dość proste w użyciu:

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

Po prostu dodaj okno dialogowe do html komponentu:

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

Dokumentacja PrimeNG PrimeFaces jest łatwa do śledzenia i bardzo precyzyjna.

Menelaos Kotsollaris
źródło
nie napotykasz problemów z uruchamianiem tematów tylko do momentu, gdy nie potrzebujesz dynamicznie tworzonego komponentu. Jeśli spróbujesz (nawet z primeng) stworzyć usługę dialogową, która korzysta z dynamicznego tworzenia komponentów - napotkasz dokładnie ten sam problem ...
DicBrus
1

Musisz go dodać entryComponents, jak określono w dokumentach .

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

Oto pełny przykład pliku modułu aplikacji z oknem dialogowym zdefiniowanym jako entryComponents.

yuval.bl
źródło
0

Jeśli jesteś podobny do mnie i gapisz się na ten wątek, myśląc: „Ale nie próbuję dodawać komponentu, próbuję dodać osłonę / usługę / rurę itp.” problem prawdopodobnie spowodował, że dodałeś niewłaściwy typ do ścieżki routingu. Tak zrobiłem. Przypadkowo dodałem zabezpieczenie do komponentu: sekcja ścieżki zamiast sekcji canActivate:. Uwielbiam autouzupełnianie IDE, ale trzeba trochę zwolnić i zwrócić uwagę. Jeśli absolutnie nie możesz go znaleźć, przeszukaj globalnie nazwę, na którą się skarży, i spójrz na każde użycie, aby upewnić się, że nie wpadłeś w błąd z nazwiskiem.

LeftOnTheMoon
źródło
0

W moim przypadku dodałem mój komponent do deklaracji i entryComponents i otrzymałem te same błędy. Musiałem także dodać MatDialogModule do importu.

Dela
źródło
0

Jeśli ktoś musi zadzwonić do Dialog z usług, tutaj jest sposób rozwiązania problemu. Zgadzam się z niektórymi z powyższych odpowiedzi, moja odpowiedź dotyczy wywoływania dialogu w usługach, jeśli ktoś może napotkać problemy.

Utwórz usługę, na przykład DialogService, a następnie przenieś funkcję dialogu do usług i dodaj swoją usługę dialogową do komponentu, który wywołujesz, jak poniżej:

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

w przeciwnym razie pojawi się błąd

MJVM
źródło