Eu tenho um conjunto de componentes angular2 que devem receber algum serviço injetado. Meu primeiro pensamento foi que seria melhor criar uma superclasse e injetar o serviço lá. Qualquer um dos meus componentes estenderia essa superclasse, mas essa abordagem não funciona.
Exemplo 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
}
}
Eu poderia resolver isso injetando MyService
dentro de cada componente e usar esse argumento para a super()
chamada, mas isso é definitivamente algum tipo de absurdo.
Como organizar meus componentes corretamente para que herdem um serviço da superclasse?
new MyService()
vez de injetar dá exatamente o mesmo resultado (exceto mais eficiente). Se você deseja compartilhar a mesma instância de serviço entre diferentes serviços e / ou componentes, isso não funcionará. Cada classe receberá outraMyService
instância.myService
. Encontrou uma solução que evita isso, mas adiciona mais código às classes derivadas ...Respostas:
Não é absurdo. É assim que os construtores e a injeção de construtor funcionam.
Cada classe injetável deve declarar as dependências como parâmetros do construtor e se a superclasse também tiver dependências, elas também precisam ser listadas no construtor da subclasse e passadas adiante para a superclasse com a
super(dep1, dep2)
chamada.Passar um injetor e adquirir dependências imperativamente tem sérias desvantagens.
Ele oculta dependências que tornam o código mais difícil de ler.
Isso viola as expectativas de alguém familiarizado com o funcionamento do Angular2 DI.
Ele interrompe a compilação offline que gera código estático para substituir DI declarativa e imperativa para melhorar o desempenho e reduzir o tamanho do código.
fonte
super
chamadas correspondentes ) a cerca de 20+ classes e esse número só vai crescer no futuro. Portanto, duas coisas: 1) Eu odiaria ver uma "grande base de código" fazer isso; e 2) Graças a Deus por vimq
e vscodectrl+.
Solução atualizada, evita que várias instâncias de myService sejam geradas usando o injetor global.
Isso garantirá que MyService possa ser usado em qualquer classe que estenda AbstractComponent sem a necessidade de injetar MyService em cada classe derivada.
Existem alguns contras para essa solução (veja Ccomment de @ Günter Zöchbauer abaixo da minha pergunta original):
Para uma explicação muito bem escrita sobre injeção de dependência no Angular2, consulte esta postagem do blog que me ajudou muito a resolver o problema: http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular- 2.html
fonte
this.myServiceA = injector.get(MyServiceA);
etc?Injector
global para evitar ter que encadear quaisquer parâmetrosAbstractComponent
? fwiw, acho que a injeção de propriedades em dependências em uma classe base amplamente usada para evitar o encadeamento de construtor confuso é uma exceção perfeitamente válida à regra usual.Em vez de injetar todos os serviços manualmente, criei uma classe que fornece os serviços, por exemplo, obtém os serviços injetados. Essa classe é então injetada nas classes derivadas e passada para a classe base.
Classe derivada:
Classe base:
Classe de prestação de serviços:
fonte
Em vez de injetar um serviço que tem todos os outros serviços como dependências, assim:
Eu pularia esta etapa extra e simplesmente adicionaria injetar todos os serviços no BaseComponent, assim:
Esta técnica assume 2 coisas:
Sua preocupação está totalmente relacionada à herança de componentes. Provavelmente, o motivo pelo qual você pousou nesta questão é por causa da quantidade esmagadora de código não seco (WET?) Que você precisa repetir em cada classe derivada. Se você deseja obter os benefícios de um único ponto de entrada para todos os seus componentes e serviços , será necessário realizar a etapa extra.
Cada componente estende o
BaseComponent
Também há uma desvantagem se você decidir usar o construtor de uma classe derivada, pois você precisará chamar
super()
e passar todas as dependências. Embora eu realmente não veja um caso de uso que necessite do uso de emconstructor
vez dengOnInit
, é inteiramente possível que exista tal caso de uso.fonte
Se a classe principal foi obtida de um plug-in de terceiros (e você não pode alterar a fonte), você pode fazer isto:
ou a melhor maneira (permaneça apenas um parâmetro no construtor):
fonte
Pelo que entendi, para herdar da classe base, primeiro você precisa instanciá-la. Para instanciá-lo, você precisa passar os parâmetros exigidos pelo construtor, portanto, você os passa do filho para o pai por meio de uma chamada super () para que faça sentido. O injetor, é claro, é outra solução viável.
fonte
HACK FEIO
Algum tempo atrás, meu cliente quer juntar dois projetos GRANDES do angular de ontem (angular v4 em angular v8). O Project v4 usa a classe BaseView para cada componente e contém o
tr(key)
método para traduções (na v8 eu uso ng-translate). Portanto, para evitar a mudança do sistema de traduções e editar centenas de modelos (na v4) ou configurar o sistema de tradução 2 em paralelo, eu uso o seguinte hack feio (não tenho orgulho disso) - naAppModule
aula, adiciono o seguinte construtor:e agora
AbstractComponent
você pode usarfonte