Eu gostaria de criar extensões para alguns componentes já implantados no Angular 2, sem precisar reescrevê-los quase completamente, pois o componente base pode sofrer alterações e desejar que essas alterações também sejam refletidas em seus componentes derivados.
Criei este exemplo simples para tentar explicar melhor minhas perguntas:
Com o seguinte 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);
}
}
Deseja criar outro componente derivativo apenas para alterar, por exemplo, um comportamento básico do componente no caso da cor de exemplo 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";
}
}
Exemplo completo de trabalho no Plunker
Nota: Obviamente, este exemplo é simples e pode ser resolvido caso contrário, não há necessidade de usar herança, mas destina-se apenas a ilustrar o problema real.
Como você pode ver na implementação do componente derivado app/my-panel.component.ts
, grande parte da implementação foi repetida, e a única parte realmente herdada foi a class
BasePanelComponent
, mas @Component
teve que ser basicamente repetida completamente, não apenas as partes alteradas, como a selector: 'my-panel'
.
Existe alguma maneira de fazer uma herança literalmente completa de um componente Angular2, herdando a class
definição das marcações / anotações, como por exemplo @Component
?
Editar 1 - Solicitação de recurso
Solicitação de recurso angular2 adicionado ao projeto no GitHub: Estender / herdar anotações de componentes angular2 # 7968
Editar 2 - Solicitação Encerrada
A solicitação foi encerrada, por esse motivo , que brevemente não saberia como mesclar o decorador. Deixando-nos sem opções. Portanto, minha opinião é citada na edição .
fonte
Respostas:
Solução alternativa:
Esta resposta de Thierry Templier é uma maneira alternativa de contornar o problema.
Após algumas perguntas com Thierry Templier, cheguei ao seguinte exemplo de trabalho que atende às minhas expectativas como alternativa à limitação de herança mencionada nesta pergunta:
1 - Crie um decorador personalizado:
2 - Componente base com o decorador @Component:
3 - Subcomponente com o decorador @CustomComponent:
Plunkr com exemplo completo.
fonte
A versão 2.3 do Angular 2 foi lançada recentemente e inclui herança de componentes nativos. Parece que você pode herdar e substituir o que quiser, exceto modelos e estilos. Algumas referências:
Novos recursos no Angular 2.3
Herança de componente em Angular 2
Um Plunkr demonstrando herança de componentes
fonte
More than one component matched on this element
caso contrário.@Component()
tag. Mas, você pode compartilhar o .html ou .css consultando o mesmo arquivo, se desejar. Em suma, é uma grande vantagem.Agora que o TypeScript 2.2 suporta Mixins através de expressões de classe , temos uma maneira muito melhor de expressar Mixins em componentes. Lembre-se de que você também pode usar a herança de componentes desde o angular 2.3 ( discussão ) ou um decorador personalizado, conforme discutido em outras respostas aqui. No entanto, acho que os Mixins têm algumas propriedades que os tornam preferíveis para reutilizar o comportamento entre os componentes:
Eu sugiro fortemente que você leia o anúncio do TypeScript 2.2 acima para entender como os Mixins funcionam. As discussões vinculadas nos problemas angulares do GitHub fornecem detalhes adicionais.
Você precisará destes tipos:
E então você pode declarar um Mixin como este
Destroyable
mixin que ajuda os componentes a acompanhar as assinaturas que precisam ser descartadasngOnDestroy
:Para misturar
Destroyable
em umComponent
, você declara seu componente assim:Observe que isso
MixinRoot
só é necessário quando você desejaextend
uma composição Mixin. Você pode estender facilmente vários mixins, por exemploA extends B(C(D))
. Esta é a linearização óbvia dos mixins que eu estava falando acima, por exemplo, você está efetivamente compondo uma hierarquia de herançaA -> B -> C -> D
.Em outros casos, por exemplo, quando você deseja compor Mixins em uma classe existente, pode aplicar o Mixin da seguinte maneira:
No entanto, achei a primeira maneira que funciona melhor para
Components
eDirectives
, como também precisa ser decorada com@Component
ou de@Directive
qualquer maneira.fonte
function Destroyable<T extends Constructor<{}>>(Base = class { } as T)
. Dessa forma, eu posso criar mixins usandoextends Destroyable()
.atualizar
A herança de componentes é suportada desde 2.3.0-rc.0
original
Até agora, o mais conveniente para mim é manter modelo e estilos em separado
*html
e*.css
arquivos e especificar aqueles através dostemplateUrl
estyleUrls
, por isso é fácil reutilizável.fonte
@Input()
e@Output()
decoradores, não é?Até onde eu sei, a herança de componentes ainda não foi implementada no Angular 2 e não tenho certeza se eles têm planos, no entanto, como o Angular 2 está usando texto datilografado (se você decidiu seguir esse caminho), pode usar a herança de classe fazendo
class MyClass extends OtherClass { ... }
. Para herança de componentes, sugiro que você se envolva com o projeto Angular 2 acessando https://github.com/angular/angular/issues e enviando uma solicitação de recurso!fonte
export class MyPanelComponent extends BasePanelComponent
), o problema é apenas no caso de Anotações / Decoradores não serem herdados.@SubComponent()
) que marque uma classe como subcomponente ou ter um campo extra no@Component
decorador que permita que você faça referência a um componente pai do qual herdar.Vamos entender algumas das principais limitações e recursos do sistema de herança de componentes da Angular.
O componente herda apenas a lógica da classe:
Esses recursos são muito importantes para ter em mente, portanto, vamos examinar cada um de forma independente.
O componente herda apenas a lógica da classe
Quando você herda um componente, toda a lógica interna é igualmente herdada. Vale a pena notar que apenas membros públicos são herdados, pois membros privados são acessíveis apenas na classe que os implementa.
Todos os metadados no decorador @Component não são herdados
O fato de nenhum metadado ser herdado pode parecer contra-intuitivo no começo, mas, se você pensar sobre isso, faz todo o sentido. Se você herdar de um Component digamos (componentA), não desejaria que o seletor de ComponentA, que você está herdando, substitua o seletor de ComponentB, que é a classe que está herdando. O mesmo pode ser dito para o template / templateUrl, bem como para o style / styleUrls.
As propriedades @Input e @Output do componente são herdadas
Esse é outro recurso que eu realmente amo sobre a herança de componentes no Angular. Em uma frase simples, sempre que você tiver uma propriedade personalizada @Input e @Output, essas propriedades serão herdadas.
O ciclo de vida do componente não é herdado
Essa parte não é tão óbvia, especialmente para pessoas que não trabalharam extensivamente com os princípios de POO. Por exemplo, digamos que você tenha o ComponentA, que implementa um dos muitos ganchos do ciclo de vida do Angular, como o OnInit. Se você criar o ComponentB e herdar o ComponentA, o ciclo de vida do OnInit do ComponentA não será acionado até você explicitamente chamá-lo, mesmo se você tiver esse ciclo de vida do OnInit para o ComponentB.
Chamando métodos de componente super / básico
Para ter o método ngOnInit () do componente ComponentA, precisamos usar a super palavra-chave e, em seguida, chamar o método que precisamos, que neste caso é ngOnInit. A super palavra-chave refere-se à instância do componente que está sendo herdado da qual, neste caso, será ComponentA.
fonte
se você ler as bibliotecas CDK e as bibliotecas de materiais, elas estão usando herança, mas não tanto para os componentes, a projeção de conteúdo é o principal IMO. veja este link https://blog.angular-university.io/angular-ng-content/ onde diz "o principal problema com esse design"
Sei que isso não responde à sua pergunta, mas realmente acho que a herança / extensão de componentes deve ser evitada . Aqui está o meu raciocínio:
Se a classe abstrata estendida por dois ou mais componentes contiver lógica compartilhada: use um serviço ou crie uma nova classe de texto datilografada que possa ser compartilhada entre os dois componentes.
Se a classe abstrata ... contiver variáveis compartilhadas ou funções onClicketc, haverá duplicação entre o html das duas visualizações de componentes estendidos. Esta é uma prática ruim e o html compartilhado precisa ser dividido em componentes. Esses componentes (peças) podem ser compartilhados entre os dois componentes.
Estou perdendo outros motivos para ter uma classe abstrata para componentes?
Um exemplo que vi recentemente foram os componentes que estendem o AutoUnsubscribe:
isso foi bas porque em uma grande base de código,
infiniteSubscriptions.push()
foi usado apenas 10 vezes. Também importar e estender,AutoUnsubscribe
na verdade, requer mais código do que apenas adicionarmySubscription.unsubscribe()
ongOnDestroy()
método do próprio componente, o que exigia lógica adicional de qualquer maneira.fonte
Se alguém está procurando uma solução atualizada, a resposta de Fernando é praticamente perfeita. Exceto que
ComponentMetadata
foi preterido. UsandoComponent
vez trabalhou para mim.O
CustomDecorator.ts
arquivo completo do Decorador personalizado é assim:Em seguida, importe-o para o seu novo
sub-component.component.ts
arquivo de componente e use em@CustomComponent
vez de@Component
:fonte
Você pode herdar @Input, @Output, @ViewChild, etc. Veja o exemplo:
fonte
Os componentes podem ser estendidos da mesma forma que uma herança de classe datilografada, apenas para substituir o seletor por um novo nome. Todas as propriedades de entrada () e saída () do componente pai funcionam normalmente
Atualizar
@Component é um decorador,
Decoradores são aplicados durante a declaração de classe e não em objetos.
Basicamente, os decoradores adicionam alguns metadados ao objeto de classe e não podem ser acessados por herança.
Se você deseja obter a herança do decorador, sugiro escrever um decorador personalizado. Algo como o exemplo abaixo.
Consulte: https://medium.com/@ttemplier/angular2-decorators-and-class-inheritance-905921dbd1b7
fonte
fonte