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.html
Este 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 .