J'essaie de créer une fabrique de composants pour un contrôleur de type popover dans mon application Angular2.

Je le fais fonctionner maintenant où je passe toutes les dépendances et mon composant au contrôleur, et crée via componentFactoryResolver.resolveComponentFactory qui fonctionne assez bien.

Je voudrais que l'appelant n'ait pas à transmettre de références aux dépendances, mais ne peut pas comprendre comment gérer cela. J'ai essayé de jouer avec ReflectiveInjector.resolveAndCreate mais je n'arrive pas à m'en sortir.

Comment configurer cela pour pouvoir accéder à ComponentFactoryResolver et ViewContainerRef sans avoir à importer et à passer via tous les consommateurs de ce service? Voir la configuration actuelle ci-dessous

Appelant / présentateur

myPopover = new PopoverController(this.componentFactoryResolver, this.viewContainerRef, MyComponent);

PopoverController

constructor (private componentFactoryResolver: ComponentFactoryResolver, private viewContainerRef: ViewContainerRef, private myComponent: Component){
    let factory = this.componentFactoryResolver.resolveComponentFactory(<Type<Component>>myComponent);
    let res = this.viewContainerRef.createComponent(factory);
}

Ce qui précède fonctionne très bien et construit parfaitement myComponent, je voudrais juste ne pas avoir à continuer à transmettre des références à ComponentFactoryResolver et viewContainer de mon appelant, qui en théorie ne devrait pas se soucier de ces services.

J'ai essayé quelque chose comme ci-dessous mais je n'ai pas réussi à le faire fonctionner

var injector = ReflectiveInjector.resolveAndCreate([ComponentFactoryResolver, ViewContainerRef]);
1
Joshua Ohana 17 janv. 2017 à 00:46

2 réponses

Meilleure réponse

ReflectiveInjector crée une nouvelle instance d'injecteur et n'est pas applicable. L'instance d'injecteur doit être transmise par référence à partir d'un autre injectable. S'il n'y a pas d'instance d'injecteur disponible, l'injecteur racine peut être obtenu avec cette technique ( et indique probablement le problème de conception).

ViewContainerRef n'est pas un service @angular/core normal, il ne fait pas référence à une instance de singleton mais à une instance qui est spécifique à un composant particulier. Il ne peut pas être récupéré avec l'injecteur.

Bien sûr, viewContainerRef doit être passé par référence.

Il a injector propriété , cela signifie qu'aucune autre dépendance ne doit être transmise avec viewContainerRef, elles peuvent être récupérées sur place:

const { injector } = viewContainerRef;
const componentFactoryResolver = injector.get(ComponentFactoryResolver);
2
Community 23 mai 2017 à 11:54

Inspiré par la réponse acceptée ci-dessus, j'ai trouvé un moyen d'utiliser Factory Providers pour accomplir cela de manière plus générique que de compter sur la relation entre les classes ViewContainerRef et ComponentFactoryResolver, bien que mon code en ait assez ironiquement besoin aussi :)

mon.service.provider.ts

import {MyService} from './my.service';
import {
  ComponentFactoryResolver,
  RendererFactory2,
  ViewContainerRef
} from '@angular/core';

const myServiceFactory = (rendererFactory, viewContainer, componentFactoryResolver) => {
  return new MyService(rendererFactory, viewContainer, componentFactoryResolver);
};

export const MyServiceProvider = {
  provide: MyService,
  useFactory: myServiceFactory,
  deps: [RendererFactory2, ViewContainerRef, ComponentFactoryResolver]
};

Extrait d'un composant nécessitant une réparation

@Component({
  ...
  providers: [MyServiceProvider],
  ...
})
0
daniel.caspers 5 sept. 2017 à 20:38