Me gustaría crear extensiones para algunos componentes ya implementados en Angular 2, sin tener que reescribirlos casi por completo, ya que el componente base podría sufrir cambios y desear que estos cambios también se reflejen en sus componentes derivados.
Creé este ejemplo simple para tratar de explicar mejor mis preguntas:
Con el siguiente componente base app/base-panel.component.ts
:
import {Component, Input} from 'angular2/core';
@Component({
selector: 'base-panel',
template: '<div class="panel" [style.background-color]="color" (click)="onClick($event)">{{content}}</div>',
styles: [`
.panel{
padding: 50px;
}
`]
})
export class BasePanelComponent {
@Input() content: string;
color: string = "red";
onClick(event){
console.log("Click color: " + this.color);
}
}
¿Desea crear otro componente derivado solo alterar, por ejemplo, un comportamiento de componente básico en el caso del color de ejemplo app/my-panel.component.ts
:
import {Component} from 'angular2/core';
import {BasePanelComponent} from './base-panel.component'
@Component({
selector: 'my-panel',
template: '<div class="panel" [style.background-color]="color" (click)="onClick($event)">{{content}}</div>',
styles: [`
.panel{
padding: 50px;
}
`]
})
export class MyPanelComponent extends BasePanelComponent{
constructor() {
super();
this.color = "blue";
}
}
Ejemplo de trabajo completo en Plunker
Nota: Obviamente, este ejemplo es simple y podría resolverse; de lo contrario, no es necesario utilizar la herencia, pero solo tiene la intención de ilustrar el problema real.
Como puede ver en la implementación del componente derivado app/my-panel.component.ts
, gran parte de la implementación se repitió, y la única parte realmente heredada fue la class
BasePanelComponent
, pero @Component
básicamente tuvo que repetirse por completo, no solo las porciones cambiadas, como la selector: 'my-panel'
.
¿Hay alguna manera de hacer una herencia literalmente completa de un componente Angular2, heredando la class
definición de las marcas / anotaciones, como por ejemplo @Component
?
Edición 1 - Solicitud de funciones
Solicitud de función angular2 agregada al proyecto en GitHub: Extender / Heredar anotaciones de componentes angular2 # 7968
Edición 2 - Solicitud cerrada
La solicitud se cerró, por este motivo , que brevemente no sabría cómo fusionar el decorador se realizará. Dejándonos sin opciones. Así que mi opinión se cita en el número .
fuente
Respuestas:
Solución alternativa:
Esta respuesta de Thierry Templier es una forma alternativa de solucionar el problema.
Después de algunas preguntas con Thierry Templier, llegué al siguiente ejemplo de trabajo que cumple con mis expectativas como una alternativa a la limitación de herencia mencionada en esta pregunta:
1 - Crear decorador personalizado:
2 - Componente base con decorador @Component:
3 - Subcomponente con el decorador @CustomComponent:
Plunkr con ejemplo completo.
fuente
Angular 2 versión 2.3 se acaba de lanzar, e incluye herencia de componentes nativos. Parece que puedes heredar y anular lo que quieras, excepto plantillas y estilos. Algunas referencias:
Nuevas características en Angular 2.3
Herencia de componentes en Angular 2
Un Plunkr que demuestra herencia de componentes
fuente
More than one component matched on this element
si no lo hace.@Component()
etiqueta. Pero, si lo desea, puede compartir .html o .css haciendo referencia al mismo archivo. En general, es una gran ventaja.Ahora que TypeScript 2.2 admite Mixins a través de expresiones de clase , tenemos una forma mucho mejor de expresar Mixins en componentes. Tenga en cuenta que también puede usar la herencia de componentes desde angular 2.3 ( discusión ) o un decorador personalizado como se describe en otras respuestas aquí. Sin embargo, creo que los Mixins tienen algunas propiedades que los hacen preferibles para reutilizar el comportamiento entre los componentes:
Le sugiero que lea el anuncio TypeScript 2.2 anterior para comprender cómo funcionan los Mixins. Las discusiones vinculadas en cuestiones angulares de GitHub proporcionan detalles adicionales.
Necesitarás estos tipos:
Y luego puede declarar un Mixin como este
Destroyable
mixin que ayuda a los componentes a realizar un seguimiento de las suscripciones que deben eliminarsengOnDestroy
:Para mezclar
Destroyable
en unComponent
, declaras tu componente así:Tenga en cuenta que
MixinRoot
solo es necesario cuando deseaextend
una composición Mixin. Puede extender fácilmente múltiples mixins, por ejemploA extends B(C(D))
. Esta es la linealización obvia de los mixins de los que hablaba anteriormente, por ejemplo, está componiendo efectivamente una jerarquía de herenciaA -> B -> C -> D
.En otros casos, por ejemplo, cuando desea componer Mixins en una clase existente, puede aplicar Mixin de la siguiente manera:
Sin embargo, descubrí que la primera forma funciona mejor
Components
yDirectives
, ya que también deben decorarse con@Component
o de@Directive
todos modos.fuente
function Destroyable<T extends Constructor<{}>>(Base = class { } as T)
. De esa manera puedo crear mixins usandoextends Destroyable()
.actualizar
La herencia de componentes es compatible desde 2.3.0-rc.0
original
Hasta el momento, el más conveniente para mí es mantener la plantilla y estilos en separada
*html
y*.css
archivos y especificar aquellos a través detemplateUrl
ystyleUrls
, lo que es fácil reutilizable.fuente
@Input()
y@Output()
decoradores, ¿verdad?Hasta donde sé, la herencia de componentes aún no se ha implementado en Angular 2 y no estoy seguro de si tienen planes, sin embargo, dado que Angular 2 está usando el mecanografiado (si ha decidido seguir esa ruta), puede usar la herencia de clase al hacerlo
class MyClass extends OtherClass { ... }
. Para la herencia de componentes, sugeriría involucrarse con el proyecto Angular 2 yendo a https://github.com/angular/angular/issues y enviando una solicitud de función.fuente
export class MyPanelComponent extends BasePanelComponent
), el problema es solo en el caso de que las Anotaciones / Decoradores no se hereden.@SubComponent()
) que marque una clase como un subcomponente o tener un campo adicional en el@Component
decorador que le permita hacer referencia a un componente principal del que heredar.Comprendamos algunas limitaciones y características clave en el sistema de herencia de componentes de Angular.
El componente solo hereda la lógica de clase:
Es muy importante tener en cuenta estas características, así que examinemos cada una de forma independiente.
El componente solo hereda la lógica de clase
Cuando hereda un Componente, toda la lógica interna es igualmente heredada. Vale la pena señalar que solo los miembros públicos se heredan ya que los miembros privados solo son accesibles en la clase que los implementa.
Todos los metadatos en el decorador @Component no se heredan
El hecho de que no se hereden metadatos puede parecer contradictorio al principio, pero, si piensas en esto, tiene mucho sentido. Si hereda de un Componente, digamos (componenteA), no querrá que el selector de ComponenteA, del que está heredando, reemplace el selector de ComponenteB, que es la clase que está heredando. Lo mismo puede decirse de template / templateUrl y de style / styleUrls.
Las propiedades del componente @Input y @Output se heredan
Esta es otra característica que realmente me encanta de la herencia de componentes en Angular. En una oración simple, siempre que tenga una propiedad personalizada @Input y @Output, estas propiedades se heredan.
El ciclo de vida de los componentes no se hereda
Esta parte es la que no es tan obvia especialmente para las personas que no han trabajado extensamente con los principios de la POO. Por ejemplo, supongamos que tiene ComponentA que implementa uno de los muchos ganchos de ciclo de vida de Angular como OnInit. Si crea ComponentB y hereda ComponentA, el ciclo de vida de OnInit de ComponentA no se activará hasta que lo llame explícitamente, incluso si tiene este ciclo de vida de OnInit para ComponentB.
Llamar a métodos de componentes Super / Base
Para tener el método ngOnInit () de ComponentA fire, necesitamos usar la palabra clave super y luego llamar al método que necesitamos que en este caso es ngOnInit. La palabra clave súper se refiere a la instancia del componente que se hereda del cual en este caso será ComponentA.
fuente
si lees las bibliotecas de CDK y las bibliotecas de materiales, están usando la herencia pero no tanto para los componentes en sí, la proyección de contenido es la OMI real. vea este enlace https://blog.angular-university.io/angular-ng-content/ donde dice "el problema clave con este diseño"
Sé que esto no responde a su pregunta, pero realmente creo que se debe evitar heredar / extender componentes . Aquí está mi razonamiento:
Si la clase abstracta extendida por dos o más componentes contiene lógica compartida: use un servicio o incluso cree una nueva clase de mecanografiado que pueda compartirse entre los dos componentes.
Si la clase abstracta ... contiene variables compartidas o funciones onClicketc, entonces habrá duplicación entre el html de las dos vistas de componentes extendidos. Esta es una mala práctica y que html compartido debe dividirse en Componente (s). Estos componentes (partes) se pueden compartir entre los dos componentes.
¿Me faltan otras razones para tener una clase abstracta para componentes?
Un ejemplo que vi recientemente fue componentes que extienden AutoUnsubscribe:
esto era bas porque en una base de código grande
infiniteSubscriptions.push()
solo se usaba 10 veces. Además, la importación y la extensión enAutoUnsubscribe
realidad requieren más código que simplemente agregarmySubscription.unsubscribe()
elngOnDestroy()
método del componente en sí, que de todos modos requería lógica adicional.fuente
Si alguien está buscando una solución actualizada, la respuesta de Fernando es bastante perfecta. Excepto que
ComponentMetadata
ha quedado en desuso. Usar enComponent
cambio funcionó para mí.El
CustomDecorator.ts
archivo completo de Custom Decorator se ve así:Luego impórtelo a su nuevo
sub-component.component.ts
archivo componente y use en@CustomComponent
lugar de@Component
esto:fuente
Puede heredar @Input, @Output, @ViewChild, etc. Mire la muestra:
fuente
Los componentes se pueden extender igual que una herencia de clase mecanografiada, solo que tiene que anular el selector con un nuevo nombre. Todas las propiedades de entrada () y salida () del componente principal funcionan normalmente
Actualizar
@Component es un decorador,
Los decoradores se aplican durante la declaración de clase no en los objetos.
Básicamente, los decoradores agregan algunos metadatos al objeto de clase y no se puede acceder a ellos por herencia.
Si desea lograr la herencia del decorador, le sugiero que escriba un decorador personalizado. Algo como el siguiente ejemplo.
Consulte: https://medium.com/@ttemplier/angular2-decorators-and-class-inheritance-905921dbd1b7
fuente
fuente