Simplificando Diferentes Tipos de Provedores de Serviços Angular
Um provedor de serviços Angular fornece uma versão de tempo de execução de um valor de dependência. Portanto, quando você injeta um serviço, o injetor de Angular examina os provedores para criar a instância do serviço.
Um provedor de serviços Angular fornece uma versão de tempo de execução de um valor de dependência. Portanto, quando você injeta um serviço, o injetor de Angular examina os provedores para criar a instância do serviço.
É o provedor que determina qual instância ou valor deve ser injetado em tempo de execução em componentes, pipes ou diretivas. Há muitos jargões envolvidos aqui, então, para entender o propósito dos tipos de fornecedores, vamos começar criando um serviço. Digamos que temos um serviço chamado ErrorService, que está apenas registrando a mensagem de erro.
import { Injectable } from '@angular/core';
@Injectable()
export class ErrorService {
logError(message: string) {
console.log(message);
}
}
Agora, podemos usar esse serviço em um componente, como mostrado na listagem abaixo:
import { Component } from '@angular/core';
import { ErrorService } from './errormessage.service';
@Component({
selector: 'app-root',
template: `
<input [(ngModel)]='err' type='text'/>
<button (click)='setError()'>set error</button>
`,
providers: [ErrorService]
})
export class AppComponent {
constructor(private errorservice: ErrorService) { }
err: string;
setError() {
this.errorservice.logError(this.err);
}
}
Estamos importando o serviço, passando para o array do provedor e injetando no construtor do componente. Estamos chamando o método de serviço ao clicar no botão, e você pode ver a mensagem de erro passada no console. Muito simples, certo?
Aqui, Angular dependerá dos valores passados no array de provedores do componente (ou módulo) para encontrar qual instância deve ser injetada em tempo de execução.
"Um Provedor determina como o objeto de determinado token pode ser criado."
Então, quando você passa um nome de serviço no array do provedor, seja de componente ou módulo, como abaixo:
providers: [ErrorService]
Aqui, Angular vai usar o valor do token ErrorService e, para o token ErrorService, ele criará o objeto da classe ErrorService. A sintaxe acima é um atalho da sintaxe abaixo:
providers: [{
provide: ErrorService, useClass: ErrorService
}]
A propriedade provide contém o token que serve como chave para
- localizando o valor da dependência.
- registering the dependency.
A segunda propriedade (de quatro tipos) é usada para criar o valor de dependência. Existem quatro valores possíveis do segundo parâmetro, conforme segue:
- useClass
- useExistente
- useValue
- useFactory
Acabamos de ver um exemplo do useClass. Agora, considere um cenário em que você tem uma nova classe para melhor registro de erros chamada NewErrorService.
import { Injectable } from '@angular/core';
@Injectable()
export class NewErrorService {
logError(message: string) {
console.log(message);
console.log('logged by DJ');
}
}
useExistente
Agora, queremos que, em vez da instância do ErrorService, a instância do NewErrorService seja injetada. Além disso, idealmente, ambas as classes devem estar implementando a mesma Interface, o que significa que terão as mesmas assinaturas de método com implementações diferentes. Agora, para o token ErrorService, queremos que a instância do NewErrorService seja injetada. Isso pode ser feito usando useClass, conforme mostrado abaixo:
providers: [
NewErrorService,
{ provide: ErrorService, useClass: NewErrorService }
]
O problema com a abordagem acima é que haverá duas instâncias do NewErrorService. Isso pode ser resolvido usando useExisting.
providers: [
NewErrorService,
{ provide: ErrorService, useExisting: NewErrorService }
]
Agora haverá apenas uma instância de NewErrorService e, para token, será criada uma instância de ErrorService de NewErrorService.
Vamos modificar o componente para usar o NewErrorService.
import { Component } from '@angular/core';
import { ErrorService } from './errormessage.service';
import { NewErrorService } from './newerrormessage.service';
@Component({
selector: 'app-root',
template: `
<input [(ngModel)]='err' type='text'/>
<button (click)='setError()'>set error</button>
<button (click)='setnewError()'>Set New eroor</button>
`,
providers: [
NewErrorService,
{ provide: ErrorService, useExisting: NewErrorService }
]
})
export class AppComponent {
constructor(private errorservice: ErrorService, private newerrorservice: NewErrorService) { }
err: string;
setError() {
this.errorservice.logError(this.err);
}
setnewError() {
this.newerrorservice.logError(this.err);
}
}
Aqui, para fins de demonstração, estou injetando serviço no componente, porém, para usar serviço no nível do módulo você pode injetar no próprio módulo. Agora, ao clicar no botão de botão de erro, NewErrorService seria chamado.
useValue
Tanto useClass quanto useExisting criam uma instância de uma classe de serviço para injetar para um token específico, mas às vezes você quer passar valor diretamente em vez de criar uma instância. Então, se você quiser passar por um objeto readymade em vez de uma instância de uma classe, pode usar useValue, como mostrado na lista abaixo:
providers: [
{
provide: ErrorService, useValue: {
logError: function (err) {
console.log('inhjected directly ' + err);
}
}
}
Aqui, estamos injetando um objeto pronto usando useValue. Então, para o token ErrorService, Angular injeta o objeto.
useFactory
Pode haver um cenário em que, até o runtime, você não tenha ideia de qual instância é necessária. Você precisa criar dependência com base em informações que só tem no último momento. Vamos considerar o exemplo de que você pode precisar criar uma instância do ServiceA se o usuário estiver logado ou do ServiceB se o usuário não estiver logado. Informações sobre usuários logados podem não estar disponíveis até a última vez ou podem mudar durante o uso do aplicativo.
Precisamos usar o useFactory quando informações sobre dependência são dinâmicas. Vamos considerar nossos dois serviços usados em exemplos anteriores:
- ErrorMessageService
- NewErrorMessageService
Para o token ErrorService em uma condição específica, queremos uma instância de ErrorMessageService ou newErrorMessageService. Podemos fazer isso usando o useFactory, como mostrado na lista abaixo:
providers: [
{
provide: ErrorService, useFactory: () => {
let m = 'old'; // this value can change
if (m === 'old') {
return new ErrorService();
} else {
return new NewErrorService();
}
}
}
]
Aqui, pegamos uma condição muito codificada. Você pode ter condições complexas para criar instâncias dinamicamente para um token específico. Além disso, lembre-se que no useFactory, você pode passar por dependência. Então suponha que você tenha dependência do LoginService para criar uma instância para o token ErrorService. Para essa passagem, o LoginService é array deps, como mostrado na listagem abaixo:
providers: [
{
provide: ErrorService, useFactory: () => {
let m = 'old'; // this value can change
if (m === 'old') {
return new ErrorService();
} else {
return new NewErrorService();
}
},
deps: [LoginService]
}
]
Estas são quatro formas de trabalhar com os prestadores de Angular. Espero que você ache este post útil. Obrigado por ler. Se você gostou deste post, por favor, compartilhe. Além disso, se você ainda não conferiu Infragistics Ignite UI for Angular Components, não deixe de conferir! Eles têm 30+ componentes de Angular baseados em material para ajudar você a programar aplicações web mais rápido.