Imagine o cenário acima, que na qual por algum motivo precisamos avisar o componente modal(Pai) que houve um click no botão(Filho), para que assim o componente pai através de um método que só ele tem contabilize o total de clicks em seu componente filho.
Então, se formos pensar em algumas possibilidades para utilizar o método que contabiliza o total de click poderíamos talvez criar uma service e remover o método do componente pai, e se você for bem "malaco" talvez possa pensar na idéia de importar o componente-pai.component.ts dentro do componente-filho.componente.ts, o que como meu líder Vitor Hugo, o "Vitão" disse, é extremamente e simplesmente proibido importar componente.ts ! haha
Então, voilà, temos a maravilhosa propriedade @Output()
Propriedade @Output()
Quando utilizamos o @Output() marcamos uma propriedade que permite o fluxo de dados do componente filho para o componente pai. Essa propriedade gera um evento que notifica para o componente pai que algo aconteceu no componente filho, e para emitirmos esse evento para o componente pai, utilizamos o EventEmiter do @angular/core.
How to do ...
Primeiro, precisamos importar o Output e nosso EventEmitter na classe do nosso componente:
import { Output, EventEmitter } from '@angular/core';
Depois, precisamos declarar nossa @Output(), que será como "a nossa fala" para nosso componente pai:
@Output() houveUmClick = new EventEmitter<void>();
constructor() {}
Nosso new EventEmitter, diz que o angular tem que criar um emissor de eventos do tipo void, mas, podemos passar string, objetos e tudo mais. Porém, em nosso exemplo precisamos só emitir que ocorreu um click, então podemos passar como void !
Depois de criado, precisamos pensar quando queremos informar para nosso componente pai que houve um click, como por exemplo no cenário abaixo:
- Quando um método retornar sucesso ou simplesmente quando for iniciado, então, declaramos:
ngOnInit(): void {
this.houveUmClick.emit();
}
Na linha de código, queremos dizer o seguinte:
- Angular, quando você iniciar o componente, fala para o componente pai que se estiver me ouvindo que houve um click e que ele resolve o que fazer, e fazemos isso através do .emit();
Caso o nosso componente pai esteja esperando alguma string ou alguma outra coisa, teríamos que ter criado um EventEmitter(); e quando fossemos emitir que houve uma ação, em nosso emit() passaríamos o que nosso componente pai esta esperando. No caso do exemplo, só precisamos alertar que houve um evento com o componente filho então podemos passar vazio.
E após isso, esta feito, nosso componente filho ja esta falando houve um evento com ele, agora nosso componente pai precisa passar a nos ouvir.
Como ouvir nosso componente filho ...
Após termos criado nossa @Output() em nosso componente filho o componente pai precisa passar a ouvir-lo, então fazemos isso da seguinte forma:
Quando declaramos nosso componente filho em nosso html, precisamos passar nele também o @Output() que criamos nele, que é a forma como ele irá falar com o componente pai, da seguinte forma:
<div class="main-content">
<app-component-button (houveUmClick)="adicionaMaisUmCickContabilizado()"></app-component-button>
</div>
Então, o houveUmClick é o nome da "forma" que nosso filho irá falar com a gente, e após ele falar, eu pego e chamo o método do componente pai que é adicionaMaisUmCickContabilizado() e nele eu faço o que é preciso.
Vale lembrar que podemos passar mais de um emissor e para mais de um componente filho. Agora, uma pergunta super válida:
- E se eu precisar que o componente "vô" do meu componente pai saiba que houve um click? Se eu precisasse subir um nível ainda na hierarquia ?
A resposta é simples, assim como criamos uma @Output() em nosso filho para que ele consiga falar, teríamos que criar uma @Output() em nosso componente pai, para que assim ele consiga conversar com o componente pai dele e o componente "vô" passaria a escuta-lo e fazer o que precisa ser feito :D
Obrigado pela leitura e até a próxima ! :D :D