LuanDantas
1/19/2018 - 12:09 PM

Angular

Snippets para Angular e TypeScript.

Serviços - Injeção de Dependência (DI) + como usar um serviço em um componente.

  • Digamos que uma Classe A precisa de uma instância de uma outra classe.
<h5>Lista de cursos</h5>

<ul>
    <li *ngFor="let curso of cursos">
        {{ curso }}
    </li>
</ul>

TypeScript

import { CursosService } from './cursos.service';

export class CursosComponent implements OnInit {

    cursos: string[] = [];
    cursosService: CursosService;

    ou 
    //cursosService: CursosService;

    constructor(_cursosService: CursosService) {
        this.cursosService = _cursosService;
    }

    ou 

    constructor(private cursosService: CursosService) {
        //this.cursosService = _cursosService;
    }

    ngOnInit() {
        this.cursos = this.cursosService.getCursos();
    }

}

Service

import { Injectable } from '@angular/core';

// Decorator para injetar a classe
@Injectable()
export class CursosService {

    getCursos() {
        return ['Angular 2', 'Java', 'Phonegap'];
    }

}

Lembrando que, a classe de serviço deverá ser informado no app.module dentro de providers: [].

Ng-Content

Tem como objetivo, passar conteúdos variáveis para um componente.

Recebe o conteúdo

<ng-content></ng-content>

Passa o conteúdo

<app-exemplo-ng-content>
    Conteúdo
</app-exemplo-ng-content>

Para passarmos mais de um valor, podemos atribuir a propriedade select e selecionarmos o que queremos passar.

<ng-content select=".titulo"></ng-content>
<ng-content select=".corpo"></ng-content>

<div class="titulo">
    <h1>Título do painel</h1>
</div>
<div class="corpo">
    <p>Corpo do painel</p>
</div>

Diretivas (If - *ngIf)

Funciona como o if da programação convencional, porém a diretiva *ngIf não contém um else.

<divc *ngIf="cursos.lenght > 0">
    Lista de cursos:    
</div>

No exemplo acima, a div somente será exibida caso o nosso array de cursos contenha algum elemento.

export class DiretivaNgIfComponent implements OnInit {
    cursos: string[] = [];
}
  • OBS: Como a nossa diretiva *ngIf manipula diretamente o DOM, devemos utilizá-la com cuidado, pois se usada de forma errada, poderemos comprometer a performance da aplicação.
  • Uma alternativa para isso, seja utilizar da Property Binding "hidden", propriedade do próprio HTML 5.
<divc [hidden]="cursos.lenght > 0">
    Lista de cursos:    
</div>

O comportamento será o mesmo, porém, poupando o DOM de ser modificado.

Angular CLI: Gerando build de Dev/Produção

Existem várias formas de se fazer, todas retornarão o mesmo resultado.

Dev

$ cd NomeProjeto
$ ng build --target=development --environment=dev
$ ng build --dev --e=dev
$ ng build --dev
$ ng build
  • O build será gerado dentro do diretório dist
  • Útil para integrar o código de backend (PHP, Java, .NET, Python, Ruby, etc...)
  • Código que dá para debugar
  • Arquivo main.bundle.js contém todo código do projeto + CSS + HTML (legível)

Produção

$ cd NomeProjeto
$ ng build --target=production --environment=prod
$ ng build --prod --env=prod
$ ng build --prod
  • Obfusca e minifica o código JS da aplicação.
  • CSS e templates HTML já minificados e incluídos em main.bundle.js

Angular CLI - Pré Processadores CSS

Utilizando pré-processadores css (sass, less ou stylus)

Ao gerar um novo projeto, o cli do Angular já possui suporte para três pré-processadores:

$ ng new meu-projeto --style=sass
$ ng new meu-projeto --style=less
$ ng new meu-projeto --style=stylus

Caso o projeto já tenha sido criado, para alterar a extensão da folha de estilo:

$ ng set defaults.styleExt scss
$ ng set defaults.styleExt less
$ ng set defaults.styleExt styl

Angular CLI

Instalação e criação de projetos: ng new, ng init e ng serve

Instalação

$ npm install -g angular-cli

Criando projeto

$ ng new NomeProjeto 
$ cd NomeProjeto 
$ ng serve

Criando components

$ ng generate component meu-primeiro-component 
ou 
$ ng g c meu-primeiro-component

Criando sercives (Serviços)

$ ng generate service meu-primeiro-servico
ou
$ ng g s meu-primeiro-servico

Arquivos (Possiveis para se criar)

- Component = $ ng g component meu-component
- Service = $ ng g service meu-servico
- Directive = $ ng g directive minha-diretiva
- Pipe = $ ng g pipe meu-pipe
- Class = $ ng g class minha-classe
- Interface = $ ng g interface minha-interface
- Enum = $ ng g enum meu-enum

Two-way Data Binding com Objetos

  • Valor do Template para o Componente e vice-versa
  • Usa-se binding de eventos + propriedades

Evento "Change" de um input

Ao digitar uma informação em um campo input, o evento será disparado.

Método 1 (Sintaxe banana na caixa - Banana in the box)

Junta-se um binding de propriedade e um binding de evento [] + () = [(ngModel)]

<input type="text" [(ngModel)]="pessoa.nome">
<input type="text" [(ngModel)]="pessoa.idade">

<p>Meu nome é {{ pessoa.nome}} e tenho {{ pessoa.idade}} anos de idade.</p>
export class DataBindingComponent implements OnInit {
  
  pessoa: any = {
    nome: 'Luan',
    idade: 25
  }
  
}

Class e Style binding

HTML - Property Binding com Classe

  • #classe - Variável local
  • (change)="0" - Fica observando o evento change do elemento
<p>Selecione uma classe</p>

<select #classe (change)="0">
    <option value="alert-succes">Sucesso</option>
    <option value="alert-info">Info</option>
    <option value="alert-warning">Alerta</option>
    <option value="alert-danger">Erro</option>
</select>

Após o evento 'onchange' ocorrer, o Angular irá fazer uma verifição

  • [class.alert-sucess] | Colchetes pois é um Style/Propery Binding e irá adicionar a classe "alert-sucess"
  • ="classe.value" | Irá fazer uma comparação com o value da variável que definimos
  • == 'alert-sucess' valor que será comparado com o value da variável que definimos
<div class="alert"
    [class.alert-sucess]="classe.value == 'alert-sucess'">
    Sucesso
</div>
<div class="alert">Info</div>
<div class="alert">Alerta</div>
<div class="alert">Erro</div>

HTML - Binding de Classe com Interpolação

Também podemos criar a mesma mecânica utilizando a Interpolação.

<div class="alert {{ classe.value }}">
    Texto colorido conforme valor do combobox.
</div>

HTML - Style binding

Podemos também, utilizar da mesma mecânica para controlar comportamentos de styles.

<div class="alert"
    [style.display]="classe.value == 'alert-danger' ? 'block' : 'none'">
    Esse texto somente aparece em caso de erro.
</div>

Escopo de serviços e módulos (Singleton x várias instâncias)

Qual a diferença entre ter várias instâncias das classes de serviços e ter apenas uma instância que seria o padrão "Singleton" para toda a aplicação.

Referência: https://www.youtube.com/watch?v=R3lU_qFsPlg

Serviços - Criando um Serviço

  • Este exemplo é o modo mais básico, e mais errado de se fazer.
<h5>Lista de cursos</h5>

<ul>
    <li *ngFor="let curso of cursos">
        {{ curso }}
    </li>
</ul>

TypeScript

import { CursosService } from './cursos.service';

export class CursosComponent implements OnInit {

    cursos: string[] = [];
    cursosService: CursosService;

    constructor() {
        this.cursosService = new CursosService();
    }

    ngOnInit() {
        this.cursos = this.cursosService.getCursos();
    }

}

Service

export class CursosService {

    getCursos() {
        return ['Angular 2', 'Java', 'Phonegap'];
    }

}

Serviços - Introdução

  • São classes que são responsaveis por fazer a comunicação com o servidor (Backend).
  • Porém os serviços também são úteis para não se repetir códigos na nossa explicação (DRY - Don't Repeat Yourself).
  • Toda a lógica de negócio deve ficar no serviço. Ou seja, os componentes deverão somente conter elementos visuais que serão apresentados para o usuário.

Criando uma diretiva: Input e Property Binding

<p highlight [defaultColor]="'grey'" [highlightColor]="'red'">
    Texto com highlight com cores customizadas.
</p>
@import { Directive, HostListener, HostBinding, Input } from '@angular/core';

@Directive({
    selector: '[highlight]'
})
export class HighlightDirective {

    @HostListener('mouseenter') onMouseOver(){
        this.backgroundColor = this.highlightColor;
    }

    @HostListener('mouseleave') onMouseLeave(){
        this.backgroundColor = this.defaultColor;
    }

    @HostBinding('style.backgroundColor') background: string;

    // Variáveis para cores dinâmicas
    @Input() defaultColor: string = 'white';
    @Input() highlightColor: string = 'yellow';

    constructor() {}

}

Angular - Criando uma diretiva: HostListener e HostBinding.

  • HostListener fica escultadno o evento no elemento hospedeiro "p".
  • HostBinding faz uma assosiação/binding de um determinado atributo ou classe de um elemento para uma variável.
<p highlightMouse>
    Texto com highlight quando passo o mouse.
</p>
import { Directive, HostListener, HostBinding, ElementRef, Rendeder } from '@angular/core';

@Directive({
    selector: '[highlightMouse]'
})
export class HighlightMouseDirective {

    @HostListener('mouseenter') onMouseOver() {
        this.backgroundColor = 'yellow';
    }

    @HostListener('mouseleave') onMouseLeave() {
        this.backgroundColor = 'white';
    }

    //Host Binding
    @HostBinding('style.backgroundColor') backgroundColor: string;
    
    constructor(){} 

}

Diretivas - Introdução

Criando uma diretiva de atributo customizada:

  • ElementRef: Faz referencia ao elemento do DOM.
  • Renderer: Renderizador, também responsável por fazer manipulações no DOM.
Criar uma diretiva para manipular o DOM.

ng g d nome-da-diretiva
<p appFundoAmarelo>
    Texto com fundo amarelo
</p>
import { Directive, Renderer } from '@angular/core'

@Directive ({
    selector: '[appFundoAmarelo]'
})

expor class NomeDaDiretiva {

    constructor(
            private _renderer: Renderer,
            private _elementRef: ElementRef
        ) {
        this._renderer.setElementStyle(
            this._elementRef.nativeElement,
            'background-color',
            'yellow'
        );
    }

}

Operador Elvis ( ? )

Tem como objetivo, fazer a verificação de um objeto é ou não nulo, de forma simples e objetiva.

export class OperadorElvisComponent implements OnInit {

    tarefa {
      desc: 'Descrição da tarefa',
      responsavel: {
          usuario: null
      }
  };

}
<p>Responsável: {{ tarefa.responsavel?.usuario?.nome }}</p>

Diretivas - ngClass

É uma alternativa para escrevermos um código menor, do que se utilizarmos class binding.

export class ngClassComponent implements OnInit {

    meuFavorito: boolean = false;

    onClick() {
        this.meuFavorito = !this.meuFavorito;
    }

}
<h1>
    <i class="glyphicon"
    [ngClass]="{
        'glyphicon-star-empty': !meuFavorito,
        'glyphicon-star': meuFavorito
    }"
    (click)="onClick()">
    </i>
</h1>

Diretivas (For - *ngFor)

É uma diretiva que permite que iteremos um array através de um loop for.

export class ngForComponent implements OnInit {

    cursos: string[] = string["Angular","Ruby"];

}

Fazemos a iteração com let e não com var, pois é uma convenção do ES6.

<ul>
    <li *ngFor="let curso of cursos">
        {{ curso }}
    </li>
</ul>

Para receber o índice de cada elemento, faremos da seguinte maneira.

<ul>
    <li *ngFor="let curso of cursos, let i = index">
       {{ i + 1 }} - {{ curso }}
    </li>
</ul>

Diretivas (Switch - *ngSwitch, *ngSwitchCase, *ngSwitchDefault)

Funciona como o switch da programação convencional.

<nav>
    <a [class.active]="aba == 'home'"
    (click)="aba = 'home'">Home</a>
    <a [class.active]="aba == 'dashboard'"
    (click)="aba = 'dashboard'">Dashboard</a>
    <a [class.active]="aba == 'campanhas'"
    (click)="aba = 'campanhas'">Campanhas</a>
</nav>

Abaixo utilizamos o Switch no formato de Property Binding, pois o elemento será ficar escutando as mudanças de status conforme a página onde estivermos.

<div [ngSwitch]="aba">
    <p *ngSwitchCase="'dashboard'">Conteúdo da Dashboard</p>
    <p *ngSwitchCase="'campanhas'">Conteúdo das Campanhas</p>
    <p *ngSwitchDefault>Conteúdo da Home</p>
</div>

Diretivas

É uma forma de passar instruções para o template.

Diretivas estruturais

Interagem com a view e modificam a estrutura do DOM e/ou código HTML. (*ngFor, *ngIf).

Diretivas de atributos

Elas não modificam a estrutura do DOM, mas elas interagem com o elemento que foram aplicadas. (ng-class, ng-style)

Angular CLI: ng lint, ng test, ng e2e

ng lint - Fazer o lint do nosso código, escanear e verificar por boas práticas. (ex: Ponto e virgulando faltando)

$ ng lint

ng test - Executar os testes unitários

$ ng test

ng e2e - Testes e2e protector

$ ng e2e

Acesso ao DOM e ao Template com ViewChild

Acessar campos e/ou valores da view através de ViewChield

<input type="text" [value]="valor" #campoInput>
import { Component, OnInit, Input, ElementRef } from '@angular/core';

export class DataBindingComponent implements OnInit {

  @ViewChield('campoInput') campoValorInput: ElementRef;
  
}

Ciclo de vida dos Components

  • ngOnChanges - (antes #2 e quando valor property-binding é atualizado)
  • ngOnInit - (quando Component é inicializado)
  • ngDoCheck - (a cada ciclo de verificaçãode mudanças)
  • ngAfterContentInit - (depois de inserir conteúdo externo na view)
  • ngAfterContentChecked - (a cada verificação de conteúdo inserido)
  • ngAfterViewChecked - (a cada verificação de conteúdo / conteúdo filho)
  • ngOnDestroy - (antes da diretiva/component ser destruído)

Customized Events - Output Properties

Emitir eventos customizados através do Output Properties. (Ex: contador com + input -)

<div>
    <button class="btn btn-primary" (click)="decrementa()">-</button>
    <input type="text" [value]="valor" readonly>
    <button class="btn btn-primary" (click)="incrementa()">+</button>
</div>
export class Component1Component implements OnInit {
  
  decrementa(){
    this.valor--;
  }
  
  incrementa(){
    this.valor++;
  }
  
}

Dessa forma, o component filho escuta e realiza toda a operação, porém, queremos que o nosso component pai também possa escutar o evento e então fazer alguma ação.

export class Component1Component implements OnInit {
  
  @Output mudouValor = new EventEmitter();
  
}

Declarar uma variável do tipo Emissor de Eventos, e o angular tem uma classe chamada de EventEmitter responsável por isso.

import { Component, OnInit, Input, EventEmitter } from '@angular/core';

Devemos importar essa propriedade 'EventEmitter' na chamada do nosso Core.

incrementa(){
    this.valor++;
    this.mudouValor.emit({ novoValor: this.valor });
}

decrementa(){
    this.valor--;
    this.mudouValor.emit({ novoValor: this.valor });
}

E emitiremos essa mudança de valor nos nossos métodos já criados.

<contador (mudouValor)="onMudouValor($event)"></contador>

Input Properties - Reutilizar components

Passar valores de um componente para outro, através das inputs properties.

Component 1

<app-curso [nome]="nomeDoCurso"></app-curso>
export class Component1Component implements OnInit {
  
  nomeDoCurso: string = 'Angular';
  
}

Component 2

import { Component, OnInit, Input } from '@angular/core';

export class Component2Component implements OnInit {
  
  @Input('nome') nomeDoCurso: string = '';
  
  ou
  
  @Input() nome: string = '';
  
}

Two-way Data Binding

  • Valor do Template para o Componente e vice-versa
  • Usa-se binding de eventos + propriedades

Evento "Change" de um input

Ao digitar uma informação em um campo input, o evento será disparado.

Método 1

<input type="text"
    [ngModel]="nome"
    (ngModelChange)="nome = $event"
>
export class DataBindingComponent implements OnInit {
  
  nome: string = 'Luan Dantas';
  
}

Método 2 (Sintaxe banana na caixa - Banana in the box)

Junta-se um binding de propriedade e um binding de evento [] + () = [(ngModel)]

<input type="text" [(ngModel)]="nome">
<p>Você digitou: {{ nome }}</p>
export class DataBindingComponent implements OnInit {
  
  nome: string = 'Luan Dantas';
  
}

Event Binding (Binding de Eventos)

Escutar eventos no HTML do Template e executar lógica de programação no Componente

Evento "Click" de um botão

Ao clicar no botão, será executada uma função criada em nosso component.

<button (click)="botaoClicado()" class="btn btn-primary">
    Me clique!
</button>
export class DataBindingComponent implements OnInit {
  
  botaoClicado(){
    alert = "O botão foi clicado!"
  }
  
}

Evento (KeyUp) ao pressionar uma tecla qualquer

Ao pressionar uma tecla, será executada uma função criada em nosso component.

<input type="text" (keyup)="onKeyup($event)" />

<p>Valor atual: {{ valorAtual }}</p>
export class DataBindingComponent implements OnInit {
  
  valorAtual: string = '';

  onKeyUp(evento: KeyBoardEvent) {
      this.valorAtual = (<HTMLInputElement>evento.target).value;
  }
}

Evento (KeyUp) ao pressionar a tecla ENTER

Ao pressionar a tecla ENTER, será executada uma função criada em nosso component.

<input type="text" #campoInput (keyup.enter)="salvarValor(campoInput.value)" />

<p>Valor salvo: {{ valorSalvo }}</p>
export class DataBindingComponent implements OnInit {
  
  valorSalvo: string = '';

  salvarValor(valor){
      this.valorSalvo = valor;
  }
}

Property Binding

  • Valor do Componente para o Template
  • Usa-se colchetes <img [src]="urlImg">
  • Quando não existe uma propriedade no elemento, usa-se [attr.cospan]

TypeScript

export class DataBindingComponent implements OnInit {
  urlImagem = "http://lorempixel.com/400/200/nature/"
}

HTML

<img [src]="urlImagem" >

Snippets e guia rápido para Angular

Interpolação

TypeScript

export class DataBindingComponent implements OnInit {
  nome: string = "Luan Dantas"
  
  getValor(){
    return 2;
  }
}

HTML

<p>{{ nome }}</p>
<p>Resultado de 1 + 1 é {{ getValor() }}</p>