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

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

Meus 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 propriedade provedores

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 .