ciclo_de_vida_de_um_componente - VWJavascript/Alurapic GitHub Wiki
Ciclo de vida de um componente
Já podemos cadastrar quantas fotos quisermos, mas o que acontecerá se uma delas tiver título com mais de 10 caracteres? As chances de ele estourar na exibição do nosso componente Painel são grandes. No lugar de limitar a quantidade de caracteres no cadastro, vamos alterar nosso componente Painel para que exiba apenas os sete primeiros caracteres do título. Para dar uma pista visual de que o título da foto é maior do que o apresentado, adicionaremos reticências no final. Sabemos que o construtor da classe do nosso componente é sempre chamado quando ele é instanciado. Sendo assim, faremos o ajuste do parâmetro passado para o titulo no construtor:
// alurapic/client/app/painel/painel.component.ts
import { Component, Input } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'painel',
templateUrl: './painel.component.html'
})
export class PainelComponent {
@Input() titulo: string;
constructor() {
this.titulo = this.titulo.length > 7 ?
this.titulo.substr(0, 7) + '...' :
this.titulo;
}
}
Quando recarregamos nossa página, nada é exibido. Olhando o console do browser temos a mensagem:
ORIGINAL EXCEPTION: TypeError: Cannot read property 'length' of undefined
Ao que tudo indica, o valor da propriedade titulo ainda não foi passado para nosso componente, porque ela é undefined. E agora?
Componentes criados pelo Angular passam por etapas específicas durante sua construção. O conjunto dessas etapas é chamado de ciclo de vida. Podemos adicionar "ganchos" para que possamos interagir com essas fases. Por exemplo, há a fase OnInit executada sempre que um valor de entrada ou de saída acontece. Há outros como OnDestroy executado quando o componente é destruído entre outros.
Para resolver nosso problema, vamos interagir com a fase OnInit,porque temos a garantia de que os parâmetros do nosso componente já foram passados. Basta adicionarmos o método ngOnInit em nosso componente para interagirmos com esta fase:
// alurapic/client/app/painel/painel.component.ts
import { Component, Input } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'painel',
templateUrl: './painel.component.html'
})
export class PainelComponent {
@Input() titulo: string;
ngOnInit() {
this.titulo = this.titulo.length > 7 ?
this.titulo.substr(0, 7) + '...' :
this.titulo;
}
}
Conseguimos o resultado esperado. No entanto, o que acontece se digitarmos incorretamente o nome do método? Por exemplo:
// alurapic/client/app/painel/painel.component.ts
import { Component, Input } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'painel',
templateUrl: './painel.component.html'
})
export class PainelComponent {
@Input() titulo: string;
// perceba que o "i" esta em minúsculo!
ngOninit() {
this.titulo = this.titulo.length > 7 ?
this.titulo.substr(0, 7) + '...' :
this.titulo;
}
}
Nada acontece. É como se esse gancho não existisse para o Angular. Para evitar cairmos nesse erro, podemos implementar uma interface, uma espécie de contrato que nos obriga a escrever o nome do método corretamente, caso contrário o compilador do TypeScript nos avisará. Ainda sem corrigir o nome do método, vamos importar a interface OnInit também do módulo @angular2/core:
import { Component, Input, OnInit } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'painel',
templateUrl: './painel.component.html'
})
export class PainelComponent implements OnInit {
@Input() titulo: string;
ngOnInit() {
this.titulo = this.titulo.length > 7 ?
this.titulo.substr(0, 7) + '...' :
this.titulo;
}
}
No Visual Studio Code, o nome da classe Painel ganha um sublinhado vermelho e quando passamos o mouse por cima temos a mensagem:
Class 'Painel' incorrectly implements interface 'OnInit'. Property 'ngOnInit' is missing in type 'Painel'.
class Painel
E se olharmos no terminal do compilador do TS temos a mensagem:
app/painel/painel.component.ts(8,14): error TS2420: Class 'PainelComponent' incorrectly implements interface 'OnInit'.
Property 'ngOnInit' is missing in type 'PainelComponent'
Veja que enquanto não implementar corretamente o método ngOnInit nosso código não compilará. Isso é interessante, porque evita que nosso código entre em produção e só depois de algum tempo descobrirmos que a troca de uma simples letra comprometeu nossa solução.
Por fim, temos a versão final do nosso PainelComponent, agora atendendo o contrato da interface:
// alurapic/client/app/painel/components/painel.ts
import { Component, Input, OnInit } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'painel',
templateUrl: './painel.component.html'
})
export class PainelComponent implements OnInit {
@Input() titulo: string;
ngOnInit() {
this.titulo = this.titulo.length > 7 ?
this.titulo.substr(0, 7) + '...' :
this.titulo;
}
}
Se você souber um pouquinho mais de ES6 pode usar template string no lugar da concatenação:
ngOnInit() {
this.titulo = this.titulo.length > 7
? `${this.titulo.substr(0, 7)}...`
: this.titulo;
}