Introdução
A estrutura Angular facilita a determinação dos fluxos de dependência de direção em um aplicativo, tornando a depuração perfeitamente fácil.
O Angular permite que dependências fornecidas por meio do injetor de um componente pai sejam compartilhadas entre seus componentes filhos, injetando-os nos construtores dos componentes filhos.
Para entender isso melhor, vamos considerar uma abordagem prática para injeção de dependência de pai para filho.
Para acompanhar este tutorial, você deve ter:
- Node.js v10.x
- Conhecimento de Angular
- Conhecimento de TypeScript
Primeiros passos
Execute o seguinte comando para criar um novo aplicativo Angular:
ng nova lista telefônica
CD em um diretório de catálogo telefônico e execute o comando abaixo no terminal para criar um módulo para a estrutura adequada de nosso aplicativo:
ng gerar contatos do módulo
Crie app/contacts/contact.model.ts
:
//app/contacts/contact.model.ts interface de exportação Contato { número de identidade; nome: string; phone_no: string; }
O snippet acima usa a interface TypeScript. Ele cria um modelo para validar os dados que serão retornados do serviço do produto.
Execute o comando abaixo para criar um serviço de contato:
ng gerar contatos/contato de serviço
Atualize contact.service.ts
:
//app/contacts/contact.service.ts import {Injetável} de'@ angular/core'; import {Contact} from'./contact.model'; @Injectable ({ fornecido em:'root' }) export class ContactService { construtor () {} getContacts (): Contact [] { Retorna [ {id: 1, nome:'Peter', phone_no:'09033940948'}, {id: 2, nome:'Sam', phone_no:'07033945948'}, {id: 3, nome:'Bryce', phone_no:'08033740948'}, {id: 4, nome:'Lee', phone_no:'090339409321'}, {id: 5, nome:'Albert', phone_no:'09066894948'} ]; } }
A propriedade providedIn
cria um provedor para o serviço. Nesse caso, providedIn:'root'
especifica que o Angular deve fornecer o serviço no injetor raiz (ou seja, torná-lo disponível em todo o aplicativo).
Agora, ContactService
pode ser injetado em qualquer lugar em nosso aplicativo.
Atualize contact-list.component.ts
:
//app/contacts/contact-list.component.ts import {Component, OnInit} de'@ angular/core'; import {Contact} from'../contact.model'; importar {ContactService} de'../contact.service'; @Componente({ seletor:'app-contact-list', templateUrl:'./contact-list.component.html', styleUrls: ['./contact-list.component.css'], provedores: [ContactService] }) export class ContactListComponent implementa OnInit { contatos: Contato []; construtor (private contactService: ContactService) {} ngOnInit (): void { this.contacts=this.contactService.getContacts (); } }
O snippet acima instancia a propriedade privada ContactService
usando a nova palavra-chave no construtor do componente, chama o método getContacts
de contactService
dentro do ngOnInit
e atribui o valor de retorno à propriedade contatos
.
Atualize contact-list.component.html
:
//app/contacts/contact-list.component.htmlMinha lista de contatos
- {{nome de contato}}
O snippet acima usa a diretiva ngFor
para exibir a lista de contatos e também aceita RecentContact
como seu componente filho direto.
Atualize app/contacts/recent-contact.component.ts
:
//app/contacts/recent-contact.component.ts import {Component, OnInit} de'@ angular/core'; importar {ContactService} de'../contact.service'; import {Contact} from'../contact.model'; @Componente({ seletor:'app-recent-contact', templateUrl:'./recent-contact.component.html', styleUrls: ['./recent-contact.component.css'] }) export class RecentContactComponent implementa OnInit { contatos: Contato []; construtor (private contactService: ContactService) {} ngOnInit (): void { this.contacts=this.contactService.getContacts (); } }
RecentContactComponent
, sendo um componente filho direto de ContactListComponent
, tem acesso à dependência fornecida de ContactListComponent
, mesmo sem realmente fornecê-la por meio do propriedade de fornecedores
do decorador @component
.
Atualize app/contacts/recent-contact.component.html
:
//app/contacts/recent-contact.component.htmlMeus contatos recentes
- {{nome de contato}}
Aqui, aplicamos o SlicePipe
à instrução ngFor
para exibir apenas os três últimos contatos.
Executando o aplicativo com o comando ng serve
, devemos ter uma lista de todos os contatos e contatos recentes processados no navegador.
Substituindo dependências no Angular
Substituir dependências no Angular requer duas propriedades principais:
-
fornecer
-aponta para a dependência que você deseja substituir -
useClass
-aponta para a nova dependência, que substituirá a dependência existente na propriedadeprovedores
Segue um formato simples:
@Component ({ provedores: [ {fornecer: serviço, useClass: FakeService} ] })
Quando substituir dependências
Há casos em que você deseja substituir a resolução padrão de sua construção.
Estes são alguns casos típicos:
- Substituindo um provedor ao escrever um teste de unidade
- Adicionar um recurso exclusivo a uma dependência sem fazer alterações nela
O último é obtido criando uma nova dependência a partir da dependência existente usando a palavra-chave extend
.
Vamos considerar uma abordagem prática para o último caso, criando um novo serviço chamado RecentContactService
que estenderia o ContactService
e filtraria os dados usando o slice
método de array em vez de usar o pipe no modelo.
Atualize recent-contact.service.ts
:
//app/contacts/recent-contact.service.ts import {Injetável} de'@ angular/core'; importar {ContactService} de'./contact.service'; import {Contact} from'./contact.model'; @Injectable ({ fornecido em:'root' }) export class RecentContactService extends ContactService { construtor () { super(); } getContacts (): Contact [] { return super.getContacts (). slice (Math.max (super.getContacts (). length-3, 0)) } }
Aqui, o método getContacts
retorna os três últimos itens da matriz resultante de ContactService
.
Agora, podemos adicionar este novo serviço (dependência) à propriedade fornecedores
de RecentContactComponent
Atualize recent-contact.component.ts
:
//app/contact/recent-contact.component.ts ... importar {RecentContactService} de'../recent-contact.service'; @Componente({ seletor:'app-recent-contact', templateUrl:'./recent-contact.component.html', styleUrls: ['./recent-contact.component.css'], provedores: [{ fornecer: ContactService, useClass: RecentContactService }] }) export class RecentContactComponent implementa OnInit { contatos: Contato []; construtor (private recentContactService: RecentContactService) {} ngOnInit (): void { this.contacts=this.recentContactService.getContacts (); } }
Aqui, a propriedade useClass
permite que o Angular substitua nossa dependência anterior ( ContactService
) por nossa nova dependência ( RecentContactService
).
Substituindo dependências por valores de string
No caso em que a dependência que queremos substituir é uma string, a sintaxe useValue
será útil.
Digamos que nosso aplicativo tenha um arquivo DBconfig
:
//app/db.config.ts interface de exportação DBConfig { nome: string; número da versão; } export const databaseSettings: DBConfig={ nome:'MongoDB', versão: 2.0 };
Para tornar as configurações do banco de dados acessíveis em nosso aplicativo, precisamos fornecer um objeto InjectionToken
:
//app/db.config.ts import {InjectionToken} de'@ angular/core'; exportar const DB_CONFIG=new InjectionToken('db.config'); ...
Agora, nosso componente pode acessar a configuração do banco de dados usando o decorador @Inject
:
//app/app.component.ts import {Component, Inject} from'@ angular/core'; importar {DB_CONFIG, databaseSettings, DBConfig} de'./db.config'; @Componente({ seletor:'app-root', templateUrl:'./app.component.html', styleUrls: ['./app.component.css'], provedores: [{ fornecer: DB_CONFIG, useValue: databaseSettings }] }) export class AppComponent { nome: string; número da versão; construtor (@Inject (DB_CONFIG) config: DBConfig) { this.name=config.name; this.version=config.version; } } //app/app.component.htmlEste aplicativo usa {{name}} Banco de dados v. {{version}}
Substituindo dependências em tempo de execução
A palavra-chave useFactory
permite que o Angular decida qual dependência injetar em uma construção em tempo de execução:
importar {RecentContactService} de'./recent-contact.service'; importar {ContactService} de'./contact.service'; função de exportação contactFactory (isRecent: boolean) { return ()=> { if (isRecent) { retornar novo RecentContactService (); } retornar novo ContactService (); }; }
O snippet acima é uma fábrica que retorna RecentContactService
ou ContactService
, dependendo da condição booleana.
Agora, podemos modificar a propriedade RecentContactComponent
de Provedores
da seguinte maneira:
... provedores: [{ fornecer: ContactService, useClass: contactFactory (true) }] ...
Com isso, podemos substituir qualquer dependência tantas vezes quanto possível. É ainda mais fácil, pois só precisamos adicionar as novas dependências à contactFactory
, ajustar as condições e, finalmente, ajustar a propriedade useClass
do componente correspondente das novas dependências.
Limitação de dependências de substituição em tempo de execução
Se qualquer uma dessas dependências injetar outras dependências em seu construtor com a implementação anterior da contactFactory
, o Angular gerará um erro.
Supondo que RecentContactService
e ContactService
sejam dependentes da dependência AuthService
, teremos que ajustar a contactFactory
da seguinte maneira:
função de exportação
contactFactory (isRecent: boolean) { return (auth: AuthService)=> { if (isRecent) { retornar novo RecentContactService (); } retornar novo ContactService (); }; }
Então, temos que adicionar a dependência AuthService
à propriedade deps
dos provedores
objeto em RecentContactComponent
como segue:
... provedores: [{ ... deps: [AuthService] }] ...
Conclusão
Trabalhar em um aplicativo Angular de grande escala requer um bom entendimento de como funciona a injeção de dependência . O conhecimento de como e quando substituir a dependência no Angular é essencial ao trabalhar em aplicativos Angular de grande escala porque ajuda a evitar a duplicação desnecessária de código em seu aplicativo.
O código-fonte deste artigo está disponível em GitHub .
A postagem Substituição de dependências na hierarquia do injetor Angular apareceu primeiro em LogRocket Blog .