ESCOPO DE INSTANCIAS DE SERVICOS E MODULOS (SINGLETON x VARIAS INSTANCIAS)
SINGLETON
O conceito de singleton pode ser defindo como uma unica instancia de um servico estara disponivel para todo o escopo da aplicacao.
Para a implementacao da classe service iremos utilizar o console.log()
para exibir a mensagem Instancia do Service
, ou seja, a cada nova instancia da classe ServiceSingletonService
uma nova mensagem sera gerada no console (no caso da classe Singleton apenas uma instancia sera usada por varios components).
UTILIZANDO ATRIBUTO providedIn
Nas versoes mais recentes do Angular, ao utilizar o objeto com atributo providedIn: 'root'
como argumento do decorator @Injectable()
, o service fica disponivel para toda a aplicacao sem a necessidade de ser declarado em nenhum _providers_
(meta-dado) de modulo.
service:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' // disponibiliza o service para o escopo global da aplicacao
})
export class ServiceSingletonService {
constructor() {
console.log('Instancia do Service')
}
getCursos(){
return ['Angular', 'NodeJs']
}
addCurso(curso: string){
this.cursos.push(curso)
}
}
ESCOPO DO SERVICE DEFINIDO NOS MODULOS
Neste nao utilizamos nenhum argumento no decorator @Injectable()
import { Injectable } from '@angular/core';
@Injectable()
export class ServiceSingletonService {
cursos: string[] = ['Angular', 'NodeJs']
constructor() {
console.log('Instancia do Service')
}
getCursos(){
return ['Angular', 'NodeJs']
}
addCurso(curso: string){
this.cursos.push(curso)
}
}
o escopo do service deve ser declarado nos respectivos modulos em ‘providers’ (meta-dado). Mesmo que declarado em mais de um modulo, apenas uma instancia do service sera construida.
IMPLEMENTACAO DO SERVICE NOS COMPONENTS
Como exemplo temos 2 components que irao utilizar um service por meio de injecao de dependencia.
component A:
import { Component, OnInit } from '@angular/core';
// import do service
import { ServiceSingletonService } from '../service-singleton.service';
@Component({
selector: 'app-component-a',
templateUrl: './component-a.component.html',
styleUrls: ['./component-a.component.css']
})
export class ComponentAComponent implements OnInit {
cursos: string[] = []
constructor(private cursosService: ServiceSingletonService) { }
ngOnInit(): void {
this.cursos = this.cursosService.getCursos()
}
onSalvarCurso(curso: string){
this.cursosService.addCurso(curso)
}
}
template do component A:
<div>
<input type="text" #cursoInput>
<button (click)="onSalvarCurso(cursoInput.value)">Add Curso</button>
<h4> Component A</h4>
<br>
<h5>Lista de cursos</h5>
<ul>
<li *ngFor="let curso of cursos">
</li>
</ul>
</div>
component B:
import { Component, OnInit } from '@angular/core';
//import do service
import { ServiceSingletonService } from '../service-singleton.service';
@Component({
selector: 'app-component-b',
templateUrl: './component-b.component.html',
styleUrls: ['./component-b.component.css']
})
export class ComponentBComponent implements OnInit {
cursos: string[] = []
constructor(private cursosService: ServiceSingletonService) { }
ngOnInit(): void {
this.cursos = this.cursosService.getCursos()
}
onSalvarCurso(curso: string){
this.cursosService.addCurso(curso)
}
}
template do component B:
<div>
<input type="text" #cursoInput>
<button (click)="onSalvarCurso(cursoInput.value)">Add Curso</button>
<h4> Component B</h4>
<br>
<h5>Lista de cursos</h5>
<ul>
<li *ngFor="let curso of cursos">
</li>
</ul>
</div>
note que as diferencas nos components e templates sao pequenas, pois possuem a mesma implementacao alternando apenas o nome da classe e os meta-dados do decorator @Component()
.
Console:
figura 1 - Service Singleton
note que ambos os components foram renderizados, porem apenas uma mensagem foi emitida no log referente a instancia do serive e ao adicionar um novo curso em qualquer um dos campos ambas as listas irao exibilo, pois compartilham o mesmo component.
#
VARIAS INSTANCIAS
Para que uma instancia de service seja acessado por um unico component (cada component possui sua respectiva instancia do service), basta declarar o _providers_
(meta-dado), no decorator @Component()
, vamos tomar o exemplo anterior alterando sua implementacao (os templates e o service permanecem iguais).
component A:
import { Component, OnInit } from '@angular/core';
import { ServiceSingletonService } from '../service-singleton.service';
@Component({
selector: 'app-component-a',
templateUrl: './component-a.component.html',
styleUrls: ['./component-a.component.css'],
providers: [ServiceSingletonService] // instancia um service para o component A
})
export class ComponentAComponent implements OnInit {
cursos: string[] = []
constructor(private cursosService: ServiceSingletonService) { }
ngOnInit(): void {
this.cursos = this.cursosService.getCursos()
}
onSalvarCurso(curso: string){
this.cursosService.addCurso(curso)
}
}
component B:
import { Component, OnInit } from '@angular/core';
import { ServiceSingletonService } from '../service-singleton.service';
@Component({
selector: 'app-component-b',
templateUrl: './component-b.component.html',
styleUrls: ['./component-b.component.css'],
providers: [ServiceSingletonService] // instancia um service para o component B
})
export class ComponentBComponent implements OnInit {
cursos: string[] = []
constructor(private cursosService: ServiceSingletonService) { }
ngOnInit(): void {
this.cursos = this.cursosService.getCursos()
}
onSalvarCurso(curso: string){
this.cursosService.addCurso(curso)
}
}
Console:
figura 2 - Service varias instancias
note que 2 mensagens “Instancia do Service” foram emitidas pelo log, logo existe uma instancia respectiva a cada component que possui sua propria lista de cursos individual.