COMUNICACAO ENTRE COMPONENTS USANDO SERVICES (BROADCASTING)
Para fazer um comparativo vamos retomar o conceito de Input properties (decorator @Input()
) utilizado para receber dados do component pai no component filho e Output properties (decorator @Output()
) utilizado para transmitir dados do component filho para o component pai. Porem no caso da utilizacao de classes que sao independentes entre si, (os components nao possuem relacao de pai e filho e cada component possui sua respectiva instancia da classe service, vide a documentacao sobre Escopo de Instancias de Services) utiliza-se classes service para realizar a transmissao de dados entre components.
component A:
import { Component, OnInit } from '@angular/core';
import { ComumService } from './../comum.service';
@Component({
selector: 'app-component-comunicacao-a',
templateUrl: './component-comunicacao-a.component.html',
styleUrls: ['./component-comunicacao-a.component.css'],
providers: [ComumService]
})
export class ComponentComunicacaoAComponent implements OnInit {
constructor(private comumService: ComumService) { }
ngOnInit(): void {
}
onSalvarCurso(curso: string){
this.comumService.addCurso(curso)
}
}
template do component A:
<div>
<input type="text" #cursoInput>
<button (click)="onSalvarCurso(cursoInput.value)">Add Curso</button>
<h4> Component Comunicacao 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 { ComumService } from './../comum.service';
@Component({
selector: 'app-component-comunicacao-b',
templateUrl: './component-comunicacao-b.component.html',
styleUrls: ['./component-comunicacao-b.component.css'],
providers: [ComumService]
})
export class ComponentComunicacaoBComponent implements OnInit {
cursos: string[] = []
constructor(private comumService: ComumService) { }
ngOnInit(): void {
this.cursos = this.comumService.getCursos()
}
onSalvarCurso(curso: string){
this.comumService.addCurso(curso)
}
}
template do component B:
<div>
<input type="text" #cursoInput>
<button (click)="onSalvarCurso(cursoInput.value)">Add Curso</button>
<h4> Component Comunicacao B</h4>
<br>
<h5>Lista de cursos</h5>
<ul>
<li *ngFor="let curso of cursos">
</li>
</ul>
</div>
comum service:
import { Injectable, EventEmitter } from '@angular/core';
@Injectable()
export class ComumService {
// emissor de evento
emitirCursoCriado = new EventEmitter<string>();
cursos: string[] = ['Angular', 'NodeJs']
constructor() {
console.log('Instancia do Service')
}
getCursos(){
return this.cursos
}
addCurso(curso: string){
this.cursos.push(curso)
// emitir curso criado
this.emitirCursoCriado.emit(curso)
}
}
#
COMUNICACAO ENTRE COMPONENTS QUE COMPARTILHAM A MESMA INSTANCIA DO SERVICE
Ao declarar o selector
de um component A no template de outro component B (o component A torna-se filho do component B) onde o component A e B necessitam das mesmas dependencias, caso nao declarada no codigo uma instancia para o component A, a instancia do component B sera automaticamente compartilhada para ambos.
Para exemplificar vamos estabelecer uma relacao entre os components por meio de seus templates.
template do component comunicacao A (component pai):
<div>
<input type="text" #cursoInput>
<button (click)="onSalvarCurso(cursoInput.value)">Add Curso</button>
<h4> Component Comunicacao A</h4>
<br>
<h5>Lista de cursos</h5>
<ul>
<li *ngFor="let curso of cursos">
</li>
</ul>
<!--declaracao do component filho no component pai-->
<app-receber-curso></app-receber-curso>
</div>
template do receber curso (component filho):
<p *ngIf="curso.length != 0">O curso criado foi </p>
component receber curso:
import { Component, OnInit } from '@angular/core';
import { ComumService } from './../../comum.service';
@Component({
selector: 'app-receber-curso',
templateUrl: './receber-curso.component.html',
styleUrls: ['./receber-curso.component.css'],
})
export class ReceberCursoComponent implements OnInit {
curso: string = ""
constructor(private comumService: ComumService) { }
ngOnInit(): void {
this.comumService.emitirCursoCriado.subscribe(
cursoCriado => this.curso = cursoCriado
)
}
}
note que ComponentComunicacaoAComponent
(component pai) ja pussui uma instancia da classe comumService
declarada em seu meta-dado providers
, logo a classe receberCurso
, recebera a mesma instancia como dependencia por padrao. Deste modo e possivel utilizar o metodo subscribe()
(sera chamado toda vez que ocorrer qualquer mudanca na respectiva instancia de comumService
), para adicionar o dado a variavel curso
declarada em ReceberCursoComponent
figura 1 - Broadcasting utilizando a mesma instancia de um service
#
COMUNICACAO ENTRE COMPONENTS COM SUAS RESPECTIVAS INSTANCIAS
Para tornar o atributo emitirCursoCriado
comum independente das instancias podemos declara-lo como static
.
comum service:
import { Injectable, EventEmitter } from '@angular/core';
@Injectable()
export class ComumService {
// emissor de evento
static emitirCursoCriadoEstatico = new EventEmitter<string>();
cursos: string[] = ['Angular', 'NodeJs']
constructor() {
console.log('Instancia do Service')
}
getCursos(){
return this.cursos
}
addCurso(curso: string){
// emitir curso criado
ComumService.emitirCursoCriadoEstatico.emit(curso)
}
}
vamos alterar a implementacao do metodo subscribe()
em ambos os components para que seja chamado a partir da classe estatica, e assim adicionar o novo curso ao array cursos
.
component A:
import { Component, OnInit } from '@angular/core';
import { ComumService } from './../comum.service';
@Component({
selector: 'app-component-comunicacao-a',
templateUrl: './component-comunicacao-a.component.html',
styleUrls: ['./component-comunicacao-a.component.css'],
providers: [ComumService]
})
export class ComponentComunicacaoAComponent implements OnInit {
cursos: string[] = []
constructor(private comumService: ComumService) { }
ngOnInit(): void {
this.cursos = this.comumService.getCursos()
// meotodo chamado a partir de atributo ESTATICO quando ha alteracoes na classe ComunService
ComumService.emitirCursoCriadoEstatico.subscribe(
curso => this.cursos.push(curso)
)
}
onSalvarCurso(curso: string){
this.comumService.addCurso(curso)
}
}
component B:
import { Component, OnInit } from '@angular/core';
import { ComumService } from './../comum.service';
@Component({
selector: 'app-component-comunicacao-b',
templateUrl: './component-comunicacao-b.component.html',
styleUrls: ['./component-comunicacao-b.component.css'],
providers: [ComumService]
})
export class ComponentComunicacaoBComponent implements OnInit {
cursos: string[] = []
constructor(private comumService: ComumService) { }
ngOnInit(): void {
this.cursos = this.comumService.getCursos()
ComumService.emitirCursoCriadoEstatico.subscribe(
cursoCriado => this.cursos.push(cursoCriado)
)
}
onSalvarCurso(curso: string){
this.comumService.addCurso(curso)
}
}
figura 2 - Broadcasting utilizando instancias diferentes de um service