services - create provider angular 2



Como faço para criar um serviço singleton no Angular 2? (8)

Atualização (Angular 6)

A maneira recomendada de criar um serviço singleton foi alterada. Recomenda-se agora especificar no decorador @Injectable no serviço que deve ser fornecido no 'root'. Isso faz muito sentido para mim e não há mais 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 lugar certo. Você também pode especificar um módulo para que ele seja fornecido apenas se o módulo for importado.

@Injectable({
  providedIn: 'root',
})
export class ApiService {
}

Atualizar (Angular 2)

Com o NgModule, 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, você importa 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

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ApiService } from './api.service';

@NgModule({
    imports: [
        CommonModule
    ],
    exports: [ // components that we want to make available
    ],
    declarations: [ // components for use in THIS module
    ],
    providers: [ // singleton services
        ApiService,
    ]
})
export class CoreModule { }

AppModule.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';

@NgModule({
    declarations: [ AppComponent ],
    imports: [
        CommonModule,
        CoreModule // will provide ApiService
    ],
    providers: [],
    bootstrap: [ AppComponent ]
})
export class AppModule { }

Resposta Original

Se você listar um provedor no bootstrap() , não precisará listá-los no decorador de componentes:

import { ApiService } from '../core/api-service';

@Component({
    selector: 'main-app',
    templateUrl: '/views/main-app.html',
    // DO NOT LIST PROVIDERS HERE IF THEY ARE IN bootstrap()!
    // (unless you want a new instance)
    //providers: [ApiService]
})
export class MainAppComponent {
    constructor(private api: ApiService) {}
}

Na verdade, listar sua classe em 'provedores' cria uma nova instância dela, se algum componente pai já a listar, as crianças não precisam, e, se o fizerem, obterão uma nova instância.

Eu li que injetar quando bootstrapping deve ter todos os filhos compartilham a mesma instância, mas os meus principais e componentes de cabeçalho (principal aplicativo inclui componente de cabeçalho e saída de roteador) estão cada um recebendo uma instância separada dos meus serviços.

Eu tenho um FacebookService que eu uso para fazer chamadas para o facebook javascript api e um UserService que usa o FacebookService. Aqui está o meu bootstrap:

bootstrap(MainAppComponent, [ROUTER_PROVIDERS, UserService, FacebookService]);

Do meu log parece que a chamada bootstrap termina, então eu vejo o FacebookService e UserService sendo criado antes do código em cada um dos construtores ser executado, o MainAppComponent, o HeaderComponent e o DefaultComponent:


  1. Se você quiser fazer singleton de serviço no nível do aplicativo, você deve defini-lo em app.module.ts

    Provedores: [MyApplicationService] (você pode definir o mesmo no módulo filho e também para torná-lo específico)

    • Não inclua este serviço no provedor que cria uma instância para aquele componente que quebra o conceito singleton, apenas injete através do construtor.
  2. Se você quiser definir o serviço singleton no serviço de criação de nível de componente, adicione esse serviço em app.module.ts e adicione a matriz de provedores dentro do componente específico, conforme mostrado abaixo do snipet.

    @Component ({seletor: 'app-root', templateUrl: './test.component.html', styleUrls: ['./test.component.scss'], provedores: [TestMyService]})

  3. 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 ao array providers [] no AppModule, você pode definir a seguinte configuração em @Injectable ():

    @Injectable ({providedIn: '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 seja o caso de serviços e aplicativos maiores em geral.


Adicionando o @Injectable decorator ao Serviço, E registrando-o como um provedor no Módulo Raiz, fará dele um singleton.


Além das excelentes respostas acima, pode haver algo mais que está faltando se as coisas em seu singleton ainda não estiverem se comportando como um singleton. Eu corri para o problema ao chamar uma função pública no singleton e descobrir que estava usando as variáveis ​​erradas. Acontece que o problema era que this não é garantido para ser vinculado ao singleton para quaisquer funções públicas no singleton. Isso pode ser corrigido seguindo o conselho here , assim:

@Injectable({
  providedIn: 'root',
})
export class SubscriptableService {
  public serviceRequested: Subject<ServiceArgs>;
  public onServiceRequested$: Observable<ServiceArgs>;

  constructor() {
    this.serviceRequested = new Subject<ServiceArgs>();
    this.onServiceRequested$ = this.serviceRequested.asObservable();

    // save context so the singleton pattern is respected
    this.requestService = this.requestService.bind(this);
  }

  public requestService(arg: ServiceArgs) {
    this.serviceRequested.next(arg);
  }
}

Alternativamente, você pode simplesmente declarar os membros da classe como public static vez de public , então o contexto não importará, mas você terá que acessá-los como SubscriptableService.onServiceRequested$ vez de usar a injeção de dependência e acessá-los via this.subscriptableService.onServiceRequested$ .


Aqui está um exemplo de trabalho com a versão 2.3 angular. Apenas chame o construtor do serviço de maneira semelhante a este construtor (private _userService: UserService). E isso criará um singleton para o aplicativo.

user.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { Subject }    from 'rxjs/Subject';
import { User } from '../object/user';


@Injectable()
export class UserService {
    private userChangedSource;
    public observableEvents;
    loggedUser:User;

    constructor() {
       this.userChangedSource = new Subject<any>();
       this.observableEvents = this.userChangedSource.asObservable();
    }

    userLoggedIn(user:User) {
        this.loggedUser = user;
        this.userChangedSource.next(user);
    }

    ...
}

app.component.ts

import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { UserService } from '../service/user.service';
import { User } from '../object/user';

@Component({
    selector: 'myApp',
    templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
    loggedUser:User;

    constructor(private _userService:UserService) { 
        this._userService.observableEvents.subscribe(user => {
                this.loggedUser = user;
                console.log("event triggered");
        });
    }
    ...
}

De Angular @ 6, você pode ter providedIn em um Injectable .

@Injectable({
  providedIn: 'root'
})
export class UserService {

}

Confira os documentos aqui

Existem duas maneiras de tornar um serviço um singleton em Angular:

  1. Declare que o serviço deve ser fornecido na raiz do aplicativo.
  2. Inclua o serviço no AppModule ou em um módulo que seja importado somente pelo AppModule.

Começando com o Angular 6.0, a maneira preferida de criar um serviço singleton é especificar no serviço que ele deve ser fornecido na raiz do aplicativo. Isso é feito configurando providedIn para root no decorador @Injectable do serviço:


Jason está completamente certo! É causado pela maneira como a injeção de dependência funciona. É baseado em injetores hierárquicos.

Existem vários injetores dentro de uma aplicação Angular2:

  • O root que você configura ao inicializar seu aplicativo
  • Um injetor por componente. Se você usar um componente dentro de outro. O injetor de componentes é um filho do componente pai. O componente de aplicação (aquele que você especifica quando aprimora seu aplicativo) tem o injetor de raiz como um pai).

Quando o Angular2 tenta injetar algo no construtor do componente:

  • Ele olha para o injetor associado ao componente. Se houver um correspondente, ele será usado para obter a instância correspondente. Esta instância é criada preguiçosamente e é um singleton para este injetor.
  • Se não houver provedor neste nível, ele irá olhar para o injetor pai (e assim por diante).

Então, se você quer ter um singleton para toda a aplicação, você precisa ter o provedor definido no nível do injetor de raiz ou do injetor de componente de aplicativo.

Mas Angular2 vai olhar para a árvore injetora do fundo. Isso significa que o provedor no nível mais baixo será usado e o escopo da instância associada será esse nível.

Veja esta pergunta para mais detalhes:


Você pode usar useValue em provedores

import { MyService } from './my.service';

@NgModule({
...
  providers: [ { provide: MyService, useValue: new MyService() } ],
...
})




angular2-services