Eu li que injetar quando o bootstrapping deve ter todos os filhos compartilhando a mesma instância, mas meus componentes principal e de cabeçalho (o aplicativo principal inclui o componente de cabeçalho e a saída do roteador) estão recebendo uma instância separada dos meus serviços.
Eu tenho um FacebookService que eu uso para fazer chamadas para a API Javascript do Facebook e um UserService que usa o FacebookService. Aqui está o meu bootstrap:
bootstrap(MainAppComponent, [ROUTER_PROVIDERS, UserService, FacebookService]);
No meu registro, parece que a chamada de autoinicialização termina, e vejo o FacebookService e o UserService sendo criados antes da execução do código em cada um dos construtores, MainAppComponent, HeaderComponent e DefaultComponent:
angular
typescript
angular2-routing
angular2-services
Jason Goemaat
fonte
fonte
UserService
eFacebookService
aproviders
nenhum outro lugar?Respostas:
Jason está completamente certo! É causada pela maneira como a injeção de dependência funciona. É baseado em injetores hierárquicos.
Existem vários injetores em um aplicativo Angular2:
Quando o Angular2 tenta injetar algo no construtor do componente:
Portanto, se você deseja ter um singleton para todo o aplicativo, é necessário que o provedor seja definido no nível do injetor raiz ou do componente do aplicativo.
Mas o Angular2 examinará a árvore do injetor por baixo. Isso significa que o provedor no nível mais baixo será usado e o escopo da instância associada será este nível.
Veja esta pergunta para mais detalhes:
fonte
Atualização (Angular 6 +)
A maneira recomendada de criar um serviço singleton mudou. Agora é recomendado especificar no
@Injectable
decorador no serviço que ele deve ser fornecido na 'raiz'. Isso faz muito sentido para mim e não há mais a necessidade de listar todos os serviços fornecidos em seus módulos. Você apenas importa os serviços quando precisa deles e eles se registram no local apropriado. Você também pode especificar um módulo para que ele seja fornecido apenas se o módulo for importado.Atualização (Angular 2)
Com o NgModule, acho que a maneira de fazer isso agora é criar um 'CoreModule' com sua classe de serviço e listar o serviço nos provedores do módulo. Em seguida, importe o módulo principal no módulo principal do aplicativo, que fornecerá a instância para todos os filhos que solicitarem essa classe em seus construtores:
CoreModule.ts
AppModule.ts
Resposta original
Se você listar um provedor
bootstrap()
, não precisará listá-lo no decorador de componentes:De fato, listar sua classe em 'fornecedores' cria uma nova instância dela, se algum componente pai já a lista, os filhos não precisam, e se o fizerem, obterão uma nova instância.
fonte
[providers]
em seu arquivo de módulo, não embootstrap()
, certo?ApiService
emAppModule
'sproviders
, e, assim, evitar a necessidade deCoreModule
? (Não sei se este é o que @JasonSwett está sugerindo.)ApiService
na parte superior, mas por que, em seguida, colocá-lo na matriz de provedores do CoreModule e depois importá-lo no app.module ... ainda não clicou em mim.TestService
seja especificado nos módulos principal e de aplicativo, as instâncias não são criadas para os módulos porque são fornecidas pelo componente para que o angular nunca chegue tão alto na árvore do injetor. Portanto, se você fornecer um serviço em seu módulo e nunca usá-lo, uma instância não parecerá criada.Eu sei que angular tem injetores hierárquicos como Thierry disse.
Mas tenho outra opção aqui, caso você encontre um caso de uso em que realmente não queira injetá-lo no pai.
Podemos conseguir isso criando uma instância do serviço e fornecendo sempre o retorno.
E, em seu componente, você usa seu método de fornecimento personalizado.
E você deve ter um serviço de singleton sem depender dos injetores hierárquicos.
Não estou dizendo que essa é uma maneira melhor, apenas no caso de alguém ter um problema em que injetores hierárquicos não são possíveis.
fonte
SHARE_SERVICE_PROVIDER
estarYOUR_SERVICE_PROVIDER
no componente? Também estou assumindo que a importação do arquivo de serviço é necessária como normal e o construtor ainda terá um parâmetro do tipo 'YourService', certo? Eu gosto disso, eu acho, permite garantir um singleton e não ter que garantir que o serviço seja fornecido na hierarquia. Ele também permite que componentes individuais obtenham sua própria cópia, apenas listando o serviço emproviders
vez do provedor singleton, certo?YOUR_SERVICE_PROVIDER
. Sim, todos os componentes obterão a mesma instância apenas adicionando-a nos provedores.instance
propriedade em um mapa de valores-chave de instânciasA sintaxe foi alterada. Verifique este link
Dependências são singletons no escopo de um injetor. No exemplo abaixo, uma única instância HeroService é compartilhada entre o HeroesComponent e seus filhos HeroListComponent.
Etapa 1. Crie uma classe singleton com o decorador @Injectable
Etapa 2. Injetar no construtor
Etapa 3. Registre o provedor
fonte
Injectable
turma não for um serviço e apenas contiverstatic
cadeias de caracteres para uso global?Adicionar
@Injectable
decorador ao Serviço e registrá-lo como um provedor no Módulo Raiz o tornará um singleton.fonte
constructor
seguinte maneira:import { SomeService } from '../../services/some/some'; @Component({ selector: 'page-selector', templateUrl: 'page.html', }) export class SomePage { constructor( public someService: SomeService ) { }
isso parece estar funcionando bem para mim
fonte
Aqui está um exemplo de trabalho com o Angular versão 2.3. Basta chamar o construtor do serviço da maneira como este construtor (private _userService: UserService). E criará um singleton para o aplicativo.
user.service.ts
app.component.ts
fonte
A
singleton service
é um serviço para o qual existe apenas uma instância em um aplicativo.Existem (2) maneiras de fornecer um serviço singleton para seu aplicativo.
use a
providedIn
propriedade ouforneça o módulo diretamente no
AppModule
aplicativoUsando o fornecido
A partir do Angular 6.0, a maneira preferida de criar um serviço singleton é configurá-lo
providedIn
como root no@Injectable()
decorador do serviço . Isso indica à Angular para fornecer o serviço na raiz do aplicativo.Matriz de provedores NgModule
Em aplicativos criados com versões Angular anteriores à 6.0, os serviços são matrizes de provedores NgModule registradas da seguinte maneira:
Se essa
NgModule
fosse a raizAppModule
, o UserService seria um singleton e disponível em todo o aplicativo. Embora você possa vê-lo codificado dessa maneira, é preferível usar aprovidedIn
propriedade do@Injectable()
decorador no próprio serviço a partir do Angular 6.0, pois ele torna seus serviços tremendos em árvore.fonte
Você pode usar
useValue
em provedoresfonte
useValue
não está relacionado ao singleton. Usevalue é apenas para passar um valor em vez de aType
(useClass
) que DI chamanew
ouuseFactory
onde é passada uma função que retorna o valor quando chamado por DI. O DI angular mantém uma única instância por provedor automaticamente. Forneça apenas uma vez e você terá um singleton. Desculpe, eu tenho que reduzir a votação porque são apenas informações inválidas: - /No Angular @ 6, você pode ter
providedIn
umInjectable
.Confira os documentos aqui
fonte
public static
.Apenas declare seu serviço como provedor apenas em app.module.ts.
Ele fez o trabalho para mim.
instancie-o usando um parâmetro privado do construtor:
ou, se o serviço for usado em html, a opção -prod reivindicará:
adicione um membro para o seu serviço e preencha-o com a instância recebida no construtor:
fonte
Se você deseja tornar o serviço único no nível do aplicativo, defina-o em app.module.ts
Provedores: [MyApplicationService] (você também pode definir o mesmo no módulo filho para torná-lo específico)
Se você deseja definir o serviço singleton no serviço de criação no nível do componente, adicione esse serviço em app.module.ts e adicione na matriz de provedores o componente específico, conforme mostrado no snipet abaixo.
@Component ({seletor: 'app-root', templateUrl: './test.component.html', styleUrls: ['./test.component.scss'], provedores: [TestMyService]})
O Angular 6 fornece uma nova maneira de adicionar serviço no nível do aplicativo. Em vez de adicionar uma classe de serviço à matriz de provedores [] no AppModule, você pode definir a seguinte configuração em @Injectable ():
@Injectable ({fornecidoIn: 'root'}) classe de exportação MyService {...}
A "nova sintaxe" oferece uma vantagem: os serviços podem ser carregados preguiçosamente pelo Angular (nos bastidores) e o código redundante pode ser removido automaticamente. Isso pode levar a um melhor desempenho e velocidade de carregamento - embora isso realmente atinja apenas serviços e aplicativos maiores em geral.
fonte
Além das excelentes respostas acima, pode haver algo que está faltando se as coisas no seu singleton ainda não estiverem se comportando como um singleton. Corri para o problema ao chamar uma função pública no singleton e descobrir que ele estava usando as variáveis erradas. Acontece que o problema era que
this
não é garantido que ele esteja vinculado ao singleton para quaisquer funções públicas no singleton. Isso pode ser corrigido seguindo os conselhos aqui , da seguinte maneira:Como alternativa, você pode simplesmente declarar os membros da classe como em
public static
vez depublic
, então o contexto não importa, mas você terá que acessá-los como emSubscriptableService.onServiceRequested$
vez de usar injeção de dependência e acessá-los viathis.subscriptableService.onServiceRequested$
.fonte
Serviços para pais e filhos
Eu estava tendo problemas com um serviço pai e seu filho usando instâncias diferentes. Para forçar uma instância a ser usada, você pode alias o pai com referência ao filho nos fornecedores do módulo de aplicativo. O pai não poderá acessar as propriedades do filho, mas a mesma instância será usada para ambos os serviços. https://angular.io/guide/dependency-injection-providers#aleased-class-providers
app.module.ts
Serviços usados por componentes fora do escopo dos módulos de aplicativos
Ao criar uma biblioteca que consiste em um componente e um serviço, deparei-me com um problema em que duas instâncias seriam criadas. Um pelo meu projeto Angular e outro pelo componente dentro da minha biblioteca. O conserto:
my-outside.component.ts
my-inside.component.ts
my-inside.component.hmtl
fonte