Tengo un conjunto de componentes de angular2 que deberían recibir algún servicio. Mi primer pensamiento fue que sería mejor crear una superclase e inyectar el servicio allí. Cualquiera de mis componentes ampliaría esa superclase, pero este enfoque no funciona.
Ejemplo simplificado:
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
}
}
Podría resolver esto inyectando MyService
dentro de todos y cada uno de los componentes y usar ese argumento para la super()
llamada, pero eso definitivamente es una especie de absurdo.
¿Cómo organizar correctamente mis componentes para que hereden un servicio de la superclase?
new MyService()
lugar de inyectar le da exactamente el mismo resultado (excepto que es más eficiente). Si desea compartir la misma instancia de servicio en diferentes servicios y / o componentes, esto no funcionará. Cada clase obtendrá otraMyService
instancia.myService
. Encontré una solución que evita esto pero agrega más código a las clases derivadas ...Respuestas:
No es absurdo. Así es como funcionan los constructores y la inyección de constructores.
Cada clase inyectable tiene que declarar las dependencias como parámetros de constructor y si la superclase también tiene dependencias, estas también deben listarse en el constructor de la subclase y pasarlas a la superclase con la
super(dep1, dep2)
llamada.Pasar un inyector y adquirir dependencias tiene serias desventajas.
Oculta dependencias que dificultan la lectura del código.
Viola las expectativas de alguien familiarizado con el funcionamiento de Angular2 DI.
Rompe la compilación fuera de línea que genera código estático para reemplazar DI declarativo e imperativo para mejorar el rendimiento y reducir el tamaño del código.
fuente
super
llamadas correspondientes ) a más de 20 clases y ese número solo aumentará en el futuro. Así que dos cosas: 1) Odiaría ver una "base de código grande" haciendo esto; y 2) Gracias a Dios por vimq
y vscodectrl+.
Solución actualizada, evita que se generen múltiples instancias de myService utilizando el inyector global.
Esto garantizará que MyService se pueda usar dentro de cualquier clase que amplíe AbstractComponent sin la necesidad de inyectar MyService en cada clase derivada.
Esta solución tiene algunas desventajas (consulte el comentario de @ Günter Zöchbauer debajo de mi pregunta original):
Para obtener una explicación muy bien escrita de la inyección de dependencia en Angular2, consulte esta publicación de blog que me ayudó mucho a resolver el problema: http://blog.ilsttram.io/angular/2015/05/18/dependency-injection-in-angular- 2.html
fuente
this.myServiceA = injector.get(MyServiceA);
etc.?Injector
global para evitar tener que encadenar parámetrosAbstractComponent
? fwiw, creo que la propiedad de inyectar dependencias en una clase base ampliamente utilizada para evitar el encadenamiento de constructores es una excepción perfectamente válida a la regla habitual.En lugar de inyectar todos los servicios manualmente, creé una clase que proporciona los servicios, por ejemplo, se inyectan los servicios. Luego, esta clase se inyecta en las clases derivadas y se pasa a la clase base.
Clase derivada:
Clase base:
Clase de prestación de servicios:
fuente
En lugar de inyectar un servicio que tiene todos los demás servicios como dependencias, así:
Me saltaría este paso adicional y simplemente agregaría inyectar todos los servicios en BaseComponent, así:
Esta técnica asume 2 cosas:
Su preocupación está completamente relacionada con la herencia de componentes. Lo más probable es que la razón por la que aterrizó en esta pregunta se deba a la abrumadora cantidad de código no seco (¿WET?) Que necesita repetir en cada clase derivada. Si desea beneficiarse de un único punto de entrada para todos sus componentes y servicios , deberá realizar un paso adicional.
Cada componente extiende el
BaseComponent
También existe una desventaja si decide usar el constructor de una clase derivada, ya que deberá llamar
super()
y pasar todas las dependencias. Aunque realmente no veo un caso de uso que requiera el uso de enconstructor
lugar dengOnInit
, es muy posible que exista tal caso de uso.fuente
Si la clase principal se obtuvo de un complemento de terceros (y no puede cambiar la fuente), puede hacer esto:
o la mejor manera (permanezca solo un parámetro en el constructor):
fuente
Por lo que entiendo, para heredar de la clase base, primero debe crear una instancia. Para crear una instancia, debe pasar los parámetros requeridos por el constructor, por lo que los pasa de hijo a padre a través de una llamada super () para que tenga sentido. El inyector, por supuesto, es otra solución viable.
fuente
Truco feo
Hace algún tiempo, algunos de mis clientes quieren unir dos GRANDES proyectos angulares a ayer (angular v4 en angular v8). Project v4 usa la clase BaseView para cada componente y contiene un
tr(key)
método para las traducciones (en v8 utilizo ng-translate). Entonces, para evitar cambiar el sistema de traducción y editar cientos de plantillas (en v4) o configurar 2 sistemas de traducción en paralelo, uso el siguiente truco feo (no estoy orgulloso de él): en laAppModule
clase agrego el siguiente constructor:y ahora
AbstractComponent
puedes usarfuente