J'ai un ensemble de composants angular2 qui devraient tous recevoir un service injecté. Ma première pensée a été qu'il serait préférable de créer une super classe et d'y injecter le service. N'importe lequel de mes composants étendrait alors cette superclasse mais cette approche ne fonctionne pas.
Exemple simplifié:
export class AbstractComponent {
constructor(private myservice: MyService) {
// Inject the service I need for all components
}
}
export MyComponent extends AbstractComponent {
constructor(private anotherService: AnotherService) {
super(); // This gives an error as super constructor needs an argument
}
}
Je pourrais résoudre cela en injectant MyService
dans chaque composant et utiliser cet argument pour l' super()
appel, mais c'est définitivement une sorte d'absurde.
Comment organiser correctement mes composants pour qu'ils héritent d'un service de la super classe?
new MyService()
au lieu d'injecter vous donne exactement le même résultat (sauf plus efficace). Si vous souhaitez partager la même instance de service entre différents services et / ou composants, cela ne fonctionnera pas. Chaque classe recevra une autreMyService
instance.myService
. Trouvé une solution qui évite cela mais ajoute plus de code aux classes dérivées ...Réponses:
Ce n'est pas absurde. C'est ainsi que fonctionnent les constructeurs et l'injection de constructeur.
Chaque classe injectable doit déclarer les dépendances en tant que paramètres de constructeur et si la superclasse a également des dépendances, celles-ci doivent également être répertoriées dans le constructeur de la sous-classe et transmises à la superclasse avec le
super(dep1, dep2)
appel.Faire le tour d'un injecteur et acquérir des dépendances présente impérativement de sérieux inconvénients.
Il cache les dépendances, ce qui rend le code plus difficile à lire.
Cela viole les attentes d'une personne familière avec le fonctionnement d'Angular2 DI.
Il interrompt la compilation hors ligne qui génère du code statique pour remplacer les DI déclaratives et impératives pour améliorer les performances et réduire la taille du code.
la source
super
appels correspondants ) à environ 20 classes et plus et ce nombre ne fera qu'augmenter dans le futur. Donc deux choses: 1) Je détesterais voir une "grande base de code" faire cela; et 2) Dieu merci pour vimq
et vscodectrl+.
Solution mise à jour, empêche la génération de plusieurs instances de myService à l'aide de l'injecteur global.
Cela garantira que MyService peut être utilisé dans n'importe quelle classe qui étend AbstractComponent sans avoir besoin d'injecter MyService dans chaque classe dérivée.
Il y a quelques inconvénients à cette solution (voir Ccomment de @ Günter Zöchbauer ci-dessous ma question initiale):
Pour une explication très bien écrite de l'injection de dépendances dans Angular2, consultez ce billet de blog qui m'a grandement aidé à résoudre le problème: http://blog.bientram.io/angular/2015/05/18/dependency-injection-in-angular- 2.html
la source
this.myServiceA = injector.get(MyServiceA);
etc.?Injector
globale pour éviter d'avoir à chaîner des paramètresAbstractComponent
? fwiw, je pense que la propriété injectant des dépendances dans une classe de base largement utilisée pour éviter le chaînage désordonné du constructeur est une exception parfaitement valable à la règle habituelle.Au lieu d'injecter manuellement tous les services, j'ai créé une classe fournissant les services, par exemple, elle obtient les services injectés. Cette classe est ensuite injectée dans les classes dérivées et transmise à la classe de base.
Classe dérivée:
Classe de base:
Classe de prestation de services:
la source
Au lieu d'injecter un service qui a tous les autres services comme dépendances, comme ceci:
Je sauterais cette étape supplémentaire et ajouterais simplement injecter tous les services dans BaseComponent, comme ceci:
Cette technique suppose 2 choses:
Votre préoccupation est entièrement liée à l'héritage des composants. Très probablement, la raison pour laquelle vous avez atterri sur cette question est à cause de la quantité écrasante de code non sec (WET?) Que vous devez répéter dans chaque classe dérivée. Si vous souhaitez bénéficier d'un point d'entrée unique pour tous vos composants et services , vous devrez effectuer l'étape supplémentaire.
Chaque composant étend la
BaseComponent
Il y a aussi un inconvénient si vous décidez d'utiliser le constructeur d'une classe dérivée, car vous devrez appeler
super()
et transmettre toutes les dépendances. Bien que je ne vois pas vraiment de cas d'utilisation qui nécessite l'utilisation deconstructor
au lieu dengOnInit
, il est tout à fait possible qu'un tel cas d'utilisation existe.la source
Si la classe parent a été obtenue à partir d'un plug-in tiers (et que vous ne pouvez pas changer la source), vous pouvez le faire:
ou la meilleure façon (ne restez qu'un seul paramètre dans le constructeur):
la source
D'après ce que je comprends, pour hériter de la classe de base, vous devez d'abord l'instancier. Afin de l'instancier, vous devez passer ses paramètres requis par le constructeur, donc vous les passez de l'enfant au parent via un appel super () pour que cela ait du sens. L'injecteur est bien sûr une autre solution viable.
la source
LAID HACK
Il y a quelque temps, certains de mes clients veulent joindre deux GRANDS projets angulaires à hier (angular v4 en angular v8). Le projet v4 utilise la classe BaseView pour chaque composant et contient une
tr(key)
méthode pour les traductions (dans la v8, j'utilise ng-translate). Donc, pour éviter de changer de système de traduction et d'éditer des centaines de modèles (en v4) ou de configurer le système de traduction 2 en parallèle, j'utilise le hack laid suivant (je n'en suis pas fier) - dans laAppModule
classe, j'ajoute le constructeur suivant:et maintenant
AbstractComponent
vous pouvez utiliserla source