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;
    }