41 votes

Angular2 RC 5. Aucune usine de composants trouvée pour les composants chargés dynamiquement

J'essaie de mettre à jour mon chargeur de composants dynamiques de RC4 à RC5 puisque le ComponentResolver est obsolète. J'ai mis à jour le chargeur comme suit

@Component({
    selector: 'component-dispatcher',
    template: `<div #container></div>` // Define the template here because of its brevity
})
export class ComponentDispatcherComponent implements OnInit, OnDestroy {
    @Input() component:any; // Some dynamic component to render
    @Input() options:any;   // Component configuration, optional
    @Input() data:any;      // Data to render within the component

    // Inject the dynamic component onto the DOM
    @ViewChild("container", {read: ViewContainerRef}) container:ViewContainerRef;

    private componentReference:ComponentRef<any>;

    constructor(private resolver:ComponentFactoryResolver) {
    }

    ngOnInit() {
        // Create our component now we're initialised
        let componentFactory = this.resolver.resolveComponentFactory(this.component);
        this.componentReference = this.container.createComponent(componentFactory);
        this.componentReference.instance.data = this.data;
        this.componentReference.instance.options = this.options;
    }

    ngOnDestroy() {
        // If we have a component, make sure we destroy it when we lose our owner
        if (this.componentReference) {
            this.componentReference.destroy();
        }
    }
}

Et tente de charger dynamiquement le composant suivant dans le DOM

@Component({
    selector: 'text-cell',
    pipes: [IterableObjectPipe],
    templateUrl: './text-cell.component.html',
    styles: ['.fieldName { font-weight: bold; }']
})
export class TextCellComponent implements OnInit {
    // Data to render within the component
    @Input() data: any;
    @Input() record: any;

    // Configuration of what data to display
    @Input() options: {
        excludeFieldNames: boolean,
        translation: string
    };

    constructor() {
    }

    ngOnInit() {
        setTimeout(() => {
            //console.log('***************************** ngOnInit...textCell ***********************');
            this.options.translation = '' + (_.get(this.options, 'translation') || 'fields');
        });
    }
}

Pourtant, lorsque je fais cela avec mon TextCellComponent ou tout autre composant de l'application, j'obtiens l'erreur suivante

ORIGINAL EXCEPTION: No component factory found for TextCellComponent
ORIGINAL STACKTRACE:
Error: No component factory found for TextCellComponent
at NoComponentFactoryError.BaseException [as constructor]      
(webpack:///./~/@angular/core/src/facade/exceptions.js?:27:23)
at new NoComponentFactoryError 

J'ai suivi les étapes de

https://angular.io/docs/ts/latest/cookbook/rc4-to-rc5.html

mais il semble que quelque chose m'échappe. J'ai essayé d'ajouter les composants au bootstrapping et de les définir globalement, mais sans succès. Toute suggestion serait la bienvenue.

EDITAR

Ajout de la définition du module

@NgModule({
    imports: [
        BrowserModule, 
        HttpModule, 
        FormsModule, 
        ReactiveFormsModule, 
        ...MATERIAL_MODULES
    ],
    declarations: [
        ...APPLICATION_PIPES, 
        ...APPLICATION_COMPONENTS, 
        ...APPLICATION_DIRECTIVES, 
        CygnusComponent,
        // Component declarations
        // TODO: refactor to appropriate modules
        ...
        ComponentDispatcherComponent,
        TextCellComponent,
        ...
    ],
    bootstrap: [
        ApplicationComponent
    ],
    providers: [
        ...APPLICATION_PROVIDERS, 
        AppStore
    ]
})
export class ApplicationComponent {}

0 votes

Avez-vous déclaré TextCellComponent dans un module quelconque ?

0 votes

Oui, il a été déclaré dans le module de premier niveau dans le tableau des déclarations.

0 votes

Y ComponentDispatcherComponent est dans le même module ?

98voto

pkozlowski.opensource Points 52557

Tous les composants destinés à être chargés "dynamiquement" doivent être déclarés dans le fichier entryComponents de votre module. En d'autres termes, vous devriez obtenir quelque chose comme :

@NgModule({
    imports: [BrowserModule, HttpModule, FormsModule, ReactiveFormsModule, ...MATERIAL_MODULES],
    declarations: [...APPLICATION_PIPES, ...APPLICATION_COMPONENTS, ...APPLICATION_DIRECTIVES, CygnusComponent,
        // Component declarations
        // TODO: refactor to appropriate modules
        ...
        ComponentDispatcherComponent,
        TextCellComponent,
        ...
    entryComponents: [TextCellComponent]
    bootstrap: [ApplicationComponent],
    providers: [...APPLICATION_PROVIDERS, AppStore]
})
export class ApplicationComponent{

Veuillez noter que vous devez énumérer les TextCellComponent en à la fois les declarations y entryComponents section.

5 votes

Que se passe-t-il si mon composant est déjà en place et que le problème persiste ?

0 votes

Toujours d'actualité dans Angular 7, j'ai passé 4 heures à chercher jusqu'à ce que je me rende compte que je devais ajouter l'élément entryComponents . - Tout est dans le tutoriel officiel d'Angular. Il est juste difficile de suivre les tutoriels sans sauter des parties.

1voto

Alan Points 55

Vous pouvez vérifier vos chemins d'importation. Dans mon cas, l'un des fichiers importés utilisait des majuscules tandis que l'autre utilisait des minuscules.

//file 1
import { IRComponent } from "./components/IR/IR.component";
//file 2
import { IRComponent } from "./components/ir/ir.component";

Dans l'onglet réseau de Chrome, j'ai remarqué que le fichier était chargé deux fois (une fois pour chaque orthographe).

1voto

George Knap Points 132

Disons que TextCellComponent est déclarée dans FooModule et votre composant responsable de la création de contenu dynamique se trouve dans le module BarModule .

Dans ce cas FooModule doit être importé dans BarModule

@NgModule({
 imports: [FooModule],
declarations: [ComponentDispatcherComponent]
})
export class BarModule {}

À mes yeux, cela compromet un peu l'idée que les choses soient dynamique . Je veux simplement un composant qui créera n'importe quel composant auquel je l'envoie par référence de classe. Si quelqu'un a une solution décente, je serais heureux de l'entendre.

0voto

G SURENDAR THINA Points 753

Il arrive que vous soyez confronté à ce problème même si vous avez indiqué le composant dans vos EntryComponents ainsi que dans vos Declarations.

Dans ce cas, il suffit d'indiquer le nom de ce composant (ici TextCellComponent ) au-dessus de tous les autres composants, comme indiqué ci-dessous :

declarations: [ 
        TextCellComponent // Declared above
        CygnusComponent,
        ComponentDispatcherComponent,
        ...
    ]

Cela doit également être fait dans les entryComponents.

J'espère que cela vous aidera.

-1voto

Nebojsa Sapic Points 1184

Vous devez importer MatDialogModule en Module pour qu'il soit informé de l'existence de la entryComponents là.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X