Вы находитесь на странице: 1из 221

Angular 2 na prtica (PT-BR)

Com Node/npm, Typescript, SystemJS e Visual Studio Code

Daniel Schmitz e Daniel Pedrinha Georgii


Esse livro est venda em http://leanpub.com/livro-angular2

Essa verso foi publicada em 2016-09-15

Esse um livro Leanpub. A Leanpub d poderes aos autores e editores a partir do processo
de Publicao Lean. Publicao Lean a ao de publicar um ebook em desenvolvimento
com ferramentas leves e muitas iteraes para conseguir feedbacks dos leitores, pivotar at
que voc tenha o livro ideal e ento conseguir trao.

2015 - 2016 Daniel Schmitz e Daniel Pedrinha Georgii


Contedo

1. Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1 Pr requisitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.1 Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.2 Servidor web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.3 Arquivo package.json . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.4 Arquivo package.json . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.5 Editores de texto e IDEs . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2 Alm do Javascript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3 TypeScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.4 Cdigo fonte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2. TypeScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1 Instalando TypeScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2 Uso do Visual Studio Code . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2.1 Detectando alteraes . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.2.2 Debug no Visual Studio Code . . . . . . . . . . . . . . . . . . . . . 24
2.2.3 Debug no navegador . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.3 Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.3.1 Tipos Bsicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.3.2 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.3.3 Enum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.3.4 Any . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.3.5 Void . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.4 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.4.1 Construtor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.4.2 Visibilidade de mtodos e propriedades . . . . . . . . . . . . . . . . 30
2.5 Herana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.6 Accessors (get/set) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
CONTEDO

2.7 Mtodos Estticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32


2.8 Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.9 Funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.9.1 Valor padro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.9.2 Valor opcional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.10 Parmetros Rest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.11 Parmetros no formato JSON . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.12 Mdulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.12.1 Exemplo com Systemjs . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.12.2 Omitindo arquivos js e map no VSCode . . . . . . . . . . . . . . . . 39
2.12.3 Uso do SystemJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.13 Decorators (ou annotation) . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.14 Concluso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

3. Um pouco de prtica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.1 Projeto AngularBase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.1.1 Configurando o projeto . . . . . . . . . . . . . . . . . . . . . . . . 47
3.1.2 Configurando a compilao do TypeScript . . . . . . . . . . . . . . 48
3.1.3 Criando o primeiro componente Angular 2 . . . . . . . . . . . . . . 50
3.1.4 Criando o mdulo . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.1.5 Criando o bootstrap . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.1.6 Criando o arquivo html . . . . . . . . . . . . . . . . . . . . . . . . 51
3.2 Criando uma pequena playlist . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.2.1 Estrutura inicial dos arquivos . . . . . . . . . . . . . . . . . . . . . 55
3.2.2 Criando um arquivo de configurao da aplicao . . . . . . . . . . 56
3.2.3 Adicionando bootstrap . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.2.4 Criando a classe Video . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.2.5 Criando uma lista simples de vdeos . . . . . . . . . . . . . . . . . 61
3.2.6 Criando sub-componentes . . . . . . . . . . . . . . . . . . . . . . . 62
3.2.7 Formatando o template . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.2.8 Repassando valores entre componentes . . . . . . . . . . . . . . . . 66
3.2.9 Selecionando um vdeo . . . . . . . . . . . . . . . . . . . . . . . . . 69
3.2.10 Eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
3.2.11 Propagando eventos . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.2.12 Exibindo os detalhes do vdeo . . . . . . . . . . . . . . . . . . . . . 73
3.2.13 Editando os dados do video selecionado . . . . . . . . . . . . . . . 76
3.2.14 Editando o ttulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
3.2.15 Criando um novo item . . . . . . . . . . . . . . . . . . . . . . . . . 82
CONTEDO

3.2.16 Algumas consideraes . . . . . . . . . . . . . . . . . . . . . . . . 83


3.3 Criando Componentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.4 Componentes Hierrquicos . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

4. Um pouco de teoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
4.1 Viso Geral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
4.2 Mdulo (module) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
4.2.1 Library Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.3 @ngModule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
4.4 Componente (component) . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
4.5 Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
4.5.1 Interpolation (Uso de {{ }}) . . . . . . . . . . . . . . . . . . . . . . . 99
4.5.2 Template Expressions . . . . . . . . . . . . . . . . . . . . . . . . . 99
4.6 Property Bind . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
4.6.1 Laos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
4.6.2 Pipes (Operador |) . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
4.7 Metadata (annotation) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
4.8 Servio (Service) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
4.9 Injeo de dependncia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
4.9.1 Uso do @Injectable() . . . . . . . . . . . . . . . . . . . . . . . . . . 104

5. Formulrios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
5.1 Criando o projeto inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
5.2 Uso do ngControl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
5.3 Exibindo uma mensagem de erro . . . . . . . . . . . . . . . . . . . . . . . 113
5.4 Desabilitando o boto de submit do formulrio . . . . . . . . . . . . . . . . 114
5.5 Submit do formulrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
5.6 Controlando a visibilidade do formulrio . . . . . . . . . . . . . . . . . . . 117

6. Conexo com o servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119


6.1 Criando o projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
6.2 Configurando o mdulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
6.3 Uso da classe Http . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
6.4 Utilizando services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
6.5 Organizao do projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
6.6 Model user . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
6.7 Service user . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
6.8 Alterando o componente AppComponent . . . . . . . . . . . . . . . . . . . 129
6.9 Enviando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
CONTEDO

7. Routes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
7.1 Aplicao AngularRoutes . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
7.2 Dividindo a aplicao em partes . . . . . . . . . . . . . . . . . . . . . . . . 133
7.3 Criando a rea onde os componentes sero carregados . . . . . . . . . . . . 133
7.4 Configurando o router . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
7.5 Criando links para as rotas . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
7.6 Repassando parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

8. Exemplo Final - Servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137


8.1 Criando o servidor RESTful . . . . . . . . . . . . . . . . . . . . . . . . . . 137
8.2 O banco de dados MongoDB . . . . . . . . . . . . . . . . . . . . . . . . . . 137
8.3 Criando o projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
8.4 Estrutura do projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
8.5 Configurando os modelos do MondoDB . . . . . . . . . . . . . . . . . . . . 142
8.6 Configurando o servidor Express . . . . . . . . . . . . . . . . . . . . . . . 144
8.7 Testando o servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
8.8 Testando a api sem o Angular . . . . . . . . . . . . . . . . . . . . . . . . . 154

9. Exemplo Final - Cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160


9.1 Arquivos iniciais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
9.2 Preparando o Template base da aplicao . . . . . . . . . . . . . . . . . . . 166
9.3 Implementando o roteamento (Router) . . . . . . . . . . . . . . . . . . . . 168
9.3.1 Criando componentes . . . . . . . . . . . . . . . . . . . . . . . . . 168
9.3.2 Configurando o @RouteConfig . . . . . . . . . . . . . . . . . . . . 170
9.3.3 Configurando o menu . . . . . . . . . . . . . . . . . . . . . . . . . 171
9.3.4 Configurando o router-outlet . . . . . . . . . . . . . . . . . . . . . 172
9.4 Exibindo Posts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
9.5 Login . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
9.6 Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
9.6.1 LoginService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
9.6.2 UserService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
9.6.3 HeadersService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
9.7 Conectando no servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
9.8 Posts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
9.8.1 PostService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
9.9 Refatorando a tela inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
9.10 Concluso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192

10. Utilizando Sublime Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193


CONTEDO

10.1 Instalao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193


10.2 Adicionando suporte a linguagem TypeScript . . . . . . . . . . . . . . . . . 193
10.3 Automatizando a build TypeScript . . . . . . . . . . . . . . . . . . . . . . . 195

11. Publicando a aplicao em um servidor cloud . . . . . . . . . . . . . . . . . . 197


11.1 Criando a conta na Digital Ocean . . . . . . . . . . . . . . . . . . . . . . . 197
11.2 Criando o droplet (servidor) . . . . . . . . . . . . . . . . . . . . . . . . . . 198
11.3 Configurando o acesso SSH . . . . . . . . . . . . . . . . . . . . . . . . . . 200
11.4 Criando o usurio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
11.5 Instalando o git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
11.6 Instalando Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
11.7 Instalando o nginx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
11.8 Instalando os mdulos do node . . . . . . . . . . . . . . . . . . . . . . . . 207
11.9 Recompilando os arquivos TypeScript . . . . . . . . . . . . . . . . . . . . . 207
11.10 Teste inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
11.11 Integrao entre nginx e node . . . . . . . . . . . . . . . . . . . . . . . . . 208
11.12 Algumas consideraes sobre node+nginx . . . . . . . . . . . . . . . . . . 212
11.13 Domnio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
11.14 Concluso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
CONTEDO 1

Uma nota sobre PIRATARIA


Esta obra no gratuita e no deve ser publicada em sites de domnio pblico como o scrib.
Por favor, contribua para que o autor invista cada vez mais em contedo de qualidade na
lngua portuguesa, o que muito escasso. Publicar um ebook sempre foi um risco quanto a
pirataria, pois muito fcil distribuir o arquivo pdf.
Se voc obteve esta obra sem compr-la no site https://leanpub.com/livro-angular2, pedimos
que leia o ebook e, se acreditar que o livro merea, compre-o e ajude o autor a publicar cada
vez mais. Obrigado!!
1. Introduo
Esta obra tem como objetivo apresentar o framework Angular, em sua nova verso, na qual foi
totalmente reescrita. Quase todos os conceitos da verso 1 ficaram obsoletos e novas tcnicas
esto sendo utilizadas no Angular 2, com o objetivo de prover um framework mais dinmico
e moderno.
Neste contexto, existem duas situaes em que o leitor se encontra. A primeira definida para
aqueles que j conhecem e usam o Angular, desde a sua verso 1.0, e que esto buscando uma
forma de continuarem o desenvolvimento de seus programas neste framework. A segunda
definida por aqueles que no conhecem o angular, e esto comeando agora o seu estudo.
Para queles que nunca trabalharam com o framework Angular, aprender a verso 2 logo
no incio ser uma tarefa simples, j que conceitos antigos no iro perturbar os novos
conceitos. Para quem conhece Angular 1, preciso de um pouco de pacincia para entender
as extensas mudanas no framework. O ideal que o desenvolvedor pense no Angular
2 como um novo framework, porque quase nenhum dos conceitos da verso anterior so
aproveitados.

1.1 Pr requisitos
Antes de abordarmos o Angular 2 necessrio rever algumas tecnologias que so vitais para
o desenvolvimento de qualquer biblioteca utilizando HTML/Javascript. Primeiro, usaremos
extensivamente o Node, que uma forma de executar Javascript no servidor. O uso do Node
ser vital para que possamos manipular bibliotecas em nosso projeto, que sero instaladas
atravs do gerenciador de pacotes do Node chamado npm.

1.1.1 Node

Se voc utiliza Windows, instale o node atravs do http://www.nodejs.org. Faa o download


e instale o Node e deixe selecionado a opo npm, que o gerenciador de pacotes do node.
Alm do node, til instalar tambm o GIT, disponvel em https://git-scm.com/.
No Linux, podemos usar o gerenciador de pacotes apt-get para instalar tudo que precisamos,
bastando apenas executar o seguinte comando:
http://www.nodejs.org
https://git-scm.com/
Introduo 3

$ sudo apt-get install git npm

Aps instalar todos os pacotes necessrios, necessrio criar um link simblico para a palavra
node, conforme o comando a seguir:

$ sudo ln -s /usr/bin/nodejs /usr/bin/node

1.1.2 Servidor web

Para o servidor web, iremos utilizar um pequeno pacote chamado live-server. Este servidor,
escrito em node, atualiza automaticamente a pgina web quando h uma modificao no
cdigo fonte, o que ajuda no aprendizado. Para instalar o live-server, abra um terminal e
digite o seguinte comando:

$ npm install live-server -g

Neste comando, o parmetro -g indica que o pacote ser instalado globalmente ao sistema.
Desta forma, pode-se utiliz-lo em qualquer parte do sistema de arquivos.

Dicas para Windows


Para abrir um terminal no Windows, v em Iniciar, Executar e digite cmd.
Tambm pode-se clicar com o boto direito do mouse no Desktop e escolher a
opo Git Bash Here, caso tenha instalado o git.

Dicas para Linux


No Linux, para instalar o pacote globalmente, use o comando sudo, por exemplo:
sudo npm install live-server -g

1.1.3 Arquivo package.json

Em todo projeto criado iremos definir um conjunto de regras de instalao e execuo que
estaro armazenadas no arquivo package.json. Este um arquivo de configurao padro dos
projetos em Node.
Como teste, crie o diretrio test e escreva o seguinte comando no terminal:
Introduo 4

$ npm init

Uma srie de perguntas sero feitas sobre o projeto. Pode-se, neste momento, deixar o valor
padro e pressionar enter at o processo terminar. Aps o trmino, um novo arquivo ser
criado no diretrio, com o seguinte texto.

{
"name": "test",
"version": "0.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

Vamos adicionar a biblioteca angular2 a este projeto. Se no estivssemos utilizando npm,


teramos que acessar o site angular.io e realizar o download do arquivo zip da biblioteca.
Como estamos utilizando o npm, pode-se alterar o arquivo package.json para realizar a
instalao do Angular 2, o que visto a seguir.

O Angular 2 instalado de uma forma diferente em relao a outras bibliotecas


javascript. Na maioria das vezes, o comando npm install faz a instalao, mas
no caso do Angular 2 necessrio adicinar vrias bibliotecas no package.json e
somente aps isso realizar o comando npm install.

1.1.4 Arquivo package.json

Reveja o arquivo package.json e perceba que uma nova entrada chamada dependencies foi
adicionada, exibido a seguir.

angular.io
Introduo 5

{
"name": "test",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@angular/common": "2.0.0",
"@angular/compiler": "2.0.0",
"@angular/core": "2.0.0",
"@angular/forms": "2.0.0",
"@angular/http": "2.0.0",
"@angular/platform-browser": "2.0.0",
"@angular/platform-browser-dynamic": "2.0.0",
"@angular/router": "3.0.0",
"@angular/upgrade": "2.0.0",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.12",
"systemjs": "0.19.27",
"zone.js": "^0.6.23",
"angular2-in-memory-web-api": "0.0.20",
"bootstrap": "^3.3.6"
}
}

Aps alterar o arquivo package.json, execute o comando npm install.


Um novo diretrio foi criado chamado node_modules, que contm as bibliotecas do projeto
e suas dependncias.
O arquivo package.json tem diversas outras funcionalidades. Por exemplo, na entrada
scripts temos um item chamado test, que a princpio exibe uma mensagem de erro simples.
Poderamos adicionar uma nova entrada chamada start, e iniciarmos o servidor web a partir
dela, conforme o exemplo a seguir:
Introduo 6

{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "live-server --port=12345"
},
... (libs) ...
}

Em scripts adicionamos a entrada start com o comando live-server --port=12345. No


terminal, basta usar o comando npm start para automaticamente executar o live-server com
os parmetros estabelecidos, conforme a imagem a seguir.

Para saber mais sobre os tipos de scripts disponveis no arquivo package.json, acesse este
link.

1.1.5 Editores de texto e IDEs

Existem dezenas de editores de texto e IDEs no mercado. Dentre eles destacamos o Sublime
Text, Atom e Visual Studio Code. Atravs de testes realizados pelo autor, recomendamos
que o Visual Studio Code seja utilizado, pois possui um suporte melhor a algumas funci-
onalidades que iremos utilizar no desenvolvimento, como uma boa compatibilidade com a
linguagem TypeScript e acesso fcil ao Git e ao Debug.
https://docs.npmjs.com/misc/scripts
http://www.sublimetext.com/
http://atom.io
https://code.visualstudio.com/
Introduo 7

1.2 Alm do Javascript


Desde o anncio do Angular 2 foi estabelecido grandes mudanas em relao ao Angular 1,
inclusive em seu prprio nome. A biblioteca antes conhecida como Angularjs foi renomeada
apenas para Angular. Alm disso, o Angular que era mantido pelo Google recebeu suporte
tambm da Microsoft, principalmente com a compatibilidade ao TypeScript.
O Angular 2 agora tem suporte as linguagens Typescript e Dart, na qual pode-se escolher de
acordo com a sua preferncia. Claro que a linguagem javascript pode tambm ser utilizada.
Como estaremos desenvolvendo componentes no Angular 2, vamos exibir um pequeno
exemplo de como um componente no angular de acordo com as 3 linguagens disponveis.
No caso do TypeScript, podemos ter a seguinte estrutura:

import {Component} from '@angular/core'

@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

Este um exemplo simples de componente no Angular 2. Mesmo sem entender muito o que
est acontecendo, perceba que usamos o comando import para importar o Angular, e que
depois usamos a notao @Component para adicionar caractersticas a classe AppComponent,
criado atravs do comando export class.
Caso deseje escrever este componente utilizando Dart, o cdigo fica:

import 'package:angular2/angular2.dart';
import 'package:angular2/bootstrap.dart';
@Component(selector: 'my-app', template: '<h1>My First Angular 2 App</h1>')
class AppComponent {}
main() {
bootstrap(AppComponent);
}

Perceba algumas diferenas na forma de importar o Angular 2, na notao do componente


e na criao da classe AppComponent. Agora vamos dar uma olhada em como seria a criao
deste componente utilizando javascript puro:
Introduo 8

(function(app) {
app.AppComponent = ng.core
.Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>'
})
.Class({
constructor: function() {}
});
})(window.app || (window.app = {}));

Em javascript no temos a criao da classe, nem do import, e a utilizao de funes


annimas para a criao do componente.

1.3 TypeScript

Nesta obra estaremos utilizando formalmente o TypeScript, por ser uma linguagem tipada
e com diversas funcionalidades. Basicamente, o TypeScript uma linguagem com suporte
ao ES6 (ECMAScript 2015, nova especificao do JavaScript), com suporte a annotations e
suporte a tipos (definio de tipos em variveis, parmetros e retorno de mtodos).
Estaremos abordando TypeScript no captulo 2, para que possamos detalhar todas as suas
funcionalidades bsicas. necessrio conhecer o bsico do TypeScript antes de utilizarmos
o Angular 2.

1.4 Cdigo fonte

Todo o cdigo fonte desta obra est no GitHub, no seguinte endereo:


https://github.com/danielschmitz/angular2-codigos
2. TypeScript
Antes de iniciarmos o estudo sobre o Angular 2, preciso abordar a linguagem TypeScript,
que ser extensivamente utilizada nesta obra. O TypeScript pode ser considerado uma
linguagem de programao que contm as seguintes particularidades:

Compatvel com a nova especificao ECMAScript 2015 (ES6)


Linguagem tipada
Implementa Annotations
Implementa Generics

Podemos afirmar que o TypeScript torna a linguagem JavaScript semelhante s linguagens


derivadas do c, como php, c#, java etc.
Mesmo que TypeScript seja nova linguagem, ela no ser executada no navegador. Aps
escrever o cdigo TypeScript com alguma funcionalidade, preciso converter este cdigo
para JavaScript puro. No exemplo a seguir, criamos uma classe chamada User, um mtodo
construtor e outro mtodo chamado hello. Aps criar a classe, instanciamos a varivel user
repassando os dois parmetros do construtor e chamamos o mtodo hello(). Veja:

class User {
fullname : string;
constructor(firstname:string,lastname:string) {
this.fullname = firstname + " " + lastname;
}
hello():string{
return "Hello, " + this.fullname;
}
}
var user = new User("Mary", "Jane");
alert(user.hello());

Este cdigo, quando traduzido para o JavaScript, torna-se algo semelhante ao cdigo a seguir:
TypeScript 10

var User = (function () {


function User(firstname, lastname) {
this.fullname = firstname + " " + lastname;
}
User.prototype.hello = function () {
return "Hello, " + this.fullname;
};
return User;
})();
var user = new User("Mary", "Jane");
alert(user.hello());

Escrever cdigo em TypeScript te ajuda a criar programas mais estruturados, e a definio


do tipo de dados ajuda a evitar bugs. Editores de texto podem exibir erros de sintaxe, como
no exemplo a seguir com o editor Visual Studio Code:

2.1 Instalando TypeScript

O cdigo TypeScript precisa ser traduzido (chamamos este processo de transpiler) para
javascript puro. Isso pode ser realizado de diversas formas, sendo a mais simples atravs da
linha de comando. Primeiro, usamos o npm para instalar a biblioteca typescript, atravs do
seguinte comando:

$ npm i typescript -g

Aps a instalao do TypeScript globalmente, podemos utilizar o comando tsc (TypeScript


Compiler) para compilar um arquivo com a extenso ts em um arquivo js. Por exemplo, crie
o arquivo user.ts e adicione o seguinte cdigo:
TypeScript 11

class User {
fullname : string;
constructor(firstname:string,lastname:string) {
this.fullname = firstname + " " + lastname;
}
hello():string{
return "Hello, " + this.fullname;
}
}
var user = new User("Mary", "Jane");
alert(user.hello());

Aps adicionar o cdigo TypeScript no arquivo com a extenso .ts, execute o seguinte
comando:

$ tsc user.ts

Aps executar o comando tsc ser gerado o arquivo user.js com o seguinte cdigo
javascript:

var User = (function () {


function User(firstname, lastname) {
this.fullname = firstname + " " + lastname;
}
User.prototype.hello = function () {
return "Hello, " + this.fullname;
};
return User;
})();
var user = new User("Mary", "Jane");
alert(user.hello());

2.2 Uso do Visual Studio Code

Pode-se utilizar qualquer editor de textos para trabalhar com Angular 2. Nesta obra,
utilizaremos extensivamente o Visual Studio Code pois um dos editores gratuitos que possui
TypeScript 12

uma maior compatibilidade com TypeScript. Vamos criar um pequeno projeto chamado
HelloWorldVSCode demonstrando como o uso do Visual Studio Code pode acelerar nosso
desenvolvimento em Angular 2.
Como abordamos no captulo anterior, o VSCode pode ser instalado neste link. O VSCode
um editor do tipo folder based, ou seja, quando ele abre uma pasta ele tenta ler naquela
pasta algum arquivo de projeto (package.json, project.json, tsconfig.json) para adicionar as
funcionalidades de acordo com projeto em questo.
Ou seja, antes de abrir o VSCode devemos, no mnimo, criar uma pasta e criar um arquivo
de projeto. Isto feito facilmente com npm, de acordo com com a imagem a seguir:
https://code.visualstudio.com/
TypeScript 13

Aps a criao do diretrio, abra o Visual Studio Code, acesse File > Open Folder, e escolha
o diretrio recm criado. O VSCode fica semelhante a imagem a seguir:
TypeScript 14

Vamos novamente criar o arquivo user.ts dentro do diretrio HelloWorldVSCode. Pelo


VSCode, basta acessar File > New File, ou clicar no cone em destaque da imagem a seguir:
TypeScript 15

Crie o arquivo user.ts com o mesmo cdigo TypeScript anterior, conforme a imagem a
seguir:
TypeScript 16

Precisamos agora usar o conversor do TypeScript para compilar o arquivo .ts em .js. Ao
invs de usar a linha de comando, podemos configurar o prprio VSCode para isso. Primeiro,
crie o arquivo tsconfig.json com o seguinte texto:

/HelloWorldVSCode/tsconfig.json

{
"compilerOptions": {
"target": "ES6",
"module": "amd",
"sourceMap": true
}
}
TypeScript 17

O arquivo tsconfig.json ser identificado pelo VSCode e suas opes de compilao


sero utilizadas. Estas opes (target, module, sourceMap) sero teis em um projeto mais
complexo, neste projeto elas no se aplicam. Por exemplo, o module indica a forma como
iremos carregar mdulos quando estivermos trabalhando com vrios arquivos separados. O
sourceMap indica se o arquivo map ser criado o que ajudar no debug do TypeScript. J
target configura a verso ECMAScript utilizada.

Com o arquivo tsconfig criado, vamos criar uma tarefa (task) para compilar o arquivo ts.
Para isso, aperte F1 e digite configure. Surge a opo Configure Task Runner semelhante
a imagem a seguir:
TypeScript 18

Quando selecionamos Configure Task Runner, uma pasta chamada .vscode criada, jun-
tamente com o arquivo tasks.json, conforme a imagem a seguir:

O arquivo tasks.json possui diversas configuraes para diversos tipos de tarefa, mas vamos
TypeScript 19

adicionar somente o bsico para compilar o TypeScript. Apague todo o contedo do arquivo
e adicione a seguinte configurao:

/HelloWorldVSCode/.vscode/tasks.json

{
"version": "0.1.0",
"command": "tsc",
"isShellCommand": true,
"showOutput": "never"
}

Neste arquivo, criamos a tarefa cujo o comando tsc (command). Para executar esta tarefa no
VSCode, pressione CTRL+SHIFT+B, ou ento aperte F1 e digite run task build. O comando
tsc ser executado, o arquivo tsconfig.json ser lido e os arquivos js e map sero criados.

Aps alguns segundos os arquivos user.js e user.js.map sero criados, semelhante a


imagem a seguir:
TypeScript 20

Se os arquivos no forem criados, altere o atributo showOutput para always e ve-


rifique o erro em questo. Verifique tambm se o comando tsc est funcionando
na linha de comando. Este comando adicionado ao sistema quando executamos
npm i typescript -g.

Para testar o arquivo user.js no navegador, crie o arquivo index.html no diretrio


HelloWorldVSCode. Com o cursor do mouse no incio do arquivo index.html digite html:5
e pressione tab. O cdigo ser convertido em um documento html completo, conforme a
imagem a seguir:
TypeScript 21

Esta gerao de cdigo realizada pela integrao do Visual Studio Code com o emmet, que
pode ser consulta neste link.
Agora coloque o cursor antes do </body> e digite script:src:
http://docs.emmet.io/cheat-sheet/
TypeScript 22

Pressione tab e veja que o cdigo gerado foi <script src=""></script>, onde devemos
adicionar o arquivo user.js no atributo src. Aps adicion-lo, podemos finalmente testar a
aplicao no navegador. Selecione o arquivo index.html na lista de arquivos e pressione o
boto direito do mouse, escolha o item Open in terminal:
TypeScript 23

Com o terminal aberto no diretrio HelloWorldVSCode, digite live-server e aguarde a p-


gina abrir. Quando a pgina abrir, uma mensagem de alert ser exibida. No preciso fechar
o navegador ou reiniciar o live-server para alterar o cdigo TypeScript, bastando apenas
recompilar a aplicao. Por exemplo, no arquivo user.ts, onde est alert(user.hello());
altere para document.body.innerHTML = user.hello(); e depois aperte ctrl+shift+b para
recompilar o arquivo user.ts e alterar a mensagem na tela.
Aps realizar estas configuraes iniciais, o uso do TypeScript torna-se mais dinmico, pois
no ser preciso usar a linha de comando para compilao a cada alterao dos arquivos.

2.2.1 Detectando alteraes

Pode-se configurar o VSCode para compilar automaticamente o TypeScript aps uma


mudana no cdigo. Desta forma, aps salvar o arquivo .ts a alterao ser percebida e
o arquivo javascript ser gerado novamente.
Para isso, altere o arquivo tsconfig.json adicionando o item watch:true e ativando a sada
(output) para verificar se o arquivo foi compilado, conforme a configurao a seguir:
TypeScript 24

{
"compilerOptions": {
"target": "es6",
"module": "amd",
"sourceMap": true,
"watch": true
}
}

Aps a primeira compilao (ctrl+shift+b), a mensagem Watching for file changes surgir
na janela de output. Altere o arquivo user.ts e, ao salvar, uma nova compilao ser
realizada sem a necessidade de pressionar ctrl+shift+b. Para terminar o processo, aperte
F1, digite task e selecione Terminate running task.

2.2.2 Debug no Visual Studio Code

Para depurar cdigo no VSCode, clique no cone de depurao do projeto ou pressione


ctrl+shift+d. Surge a tela a seguir, a princpio sem o debug configurado:
TypeScript 25

Clique na seta verde para iniciar a primeira configurao do depurador. O arquivo .vsco-
de/launch.json ser criado, de acordo com a imagem a seguir:

Altere o parmetro program para user.js e o parmetro sourceMaps para true. Lembre que,
sempre que for depurar cdigo TypeScript, deve-se ter o sourceMap referente.
Acesse o arquivo user.ts e adicione o breakpoint no mtodo construtor, na linha 4, conforme
a imagem a seguir:
TypeScript 26

2.2.3 Debug no navegador

sempre importante ter a depurao (debug) de cdigo ativada no navegador. fundamental


gerar os arquivos .map atravs do sourceMap da configurao do .vscode/tasks.json,
ou executar o comando tsc utilizando o parmetro --sourceMap. Neste projeto, o arquivo
user.ts tem o seu arquivo compilado user.js e o seu map user.js.map, permitindo assim
que o debug seja usado.
No Google Chrome, pressione F12 e navegue at a aba sources. Encontre o arquivo user.ts
e adicione um breakpoint no mtodo hello(). Recarregue a pgina para verificar que o fluxo
de cdigo est parado na linha em que o breakpoint foi adicionado, conforme a imagem a
seguir:
TypeScript 27

2.3 Tipos
Agora que temos um ambiente de trabalho capaz de compilar os arquivos TypeScript em
JavaScript podemos iniciar o nosso estudo nesta linguagem. fundamental aprend-la para
que possamos ter xito no desenvolvimento Angular 2. Felizmente TypeScript semelhante
s linguagens derivadas da linguagem c, como java ou c#. Diferentemente do JavaScript, no
TypeScript podemos criar classes, interfaces, definir tipos de variveis e tipos de retorno de
mtodos.

2.3.1 Tipos Bsicos

Como j comentamos, com TypeScript possvel adicionar tipos s variveis. Para criar uma
varivel, usamos a seguinte sintaxe:

var NOMDE_DA_VARIAVEL : TIPO = VALOR

Os tipos bsicos existentes so:

boolean: Pode assumir os valores true ou false


number: Assume qualquer nmero, como inteiro ou ponto flutuante.
string: Tipo texto, pode ser atribudo com aspas simples ou duplas.
TypeScript 28

2.3.2 Arrays

J os Arrays no TS podem ser criados atravs de duas formas. A primeira delas, usa-se [] na
definio do tipo da varivel, veja:

var list:number[] = [1,2,3];

A segunda mais conhecida como generics e usa <> para definir o tipo, veja:

var list:Array<number> = [1,2,3];

Pode-se criar arrays de tipos complexos, como por exemplo a seguir, onde a classe Point
uma classe TypeScript criada previamente.

var arr:Array<Point> = [
new Point(10,10),
new Point(20,30),
new Point(30,10)
]

2.3.3 Enum

Tambm podemos criar Enums, que so enumeraes que podem definir um status ou um
conjunto de valores, como no exemplo a seguir:

enum Color {Red, Green, Blue};


var c: Color = Color.Green;

Enuns so facilmente manipulados atravs do Visual Studio Code, como na imagem a seguir,
com a complementao de cdigo (ctrl+espao):
TypeScript 29

2.3.4 Any

O tipo any assume qualquer tipo, sendo string, number, boolean etc.

2.3.5 Void

O void usado para determinar que um mtodo no retorna nenhum valor, conforme o
exemplo a seguir.

function warnUser(): void {


alert("This is my warning message");
}

2.4 Classes

O conceito de classes no TypeScript o mesmo de uma classe em qualquer linguagem


orientada a objetos. As classes no TypeScript seguem o padro ECMAScript 6. A classe possui
uma sintaxe muito familiar com c#, veja:

class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
var greeter = new Greeter("world");

2.4.1 Construtor

O construtor definido pela palavra constructor. Mtodos no necessitam da palavra


function, bastando apenas usar nomedometodo().
TypeScript 30

2.4.2 Visibilidade de mtodos e propriedades

Perceba que, no exemplo apresentado, no definimos visibilidade das propriedades da classe,


nem o tipo de retorno do mtodo greet. claro que podemos definir estes parmetros,
conforme o prximo exemplo.

class Greeter {
private greeting: string;
constructor(message: string) {
this.greeting = message;
}
public greet() : string {
return "Hello, " + this.greeting;
}
}

var greeter:Greeter = new Greeter("world");

Mtodos e propriedades de uma classe podem assumir a visibilidade: private, public e


protected.

private: So visveis apenas na prpria classe.


public: So visveis em todas as classes.
protected: So visveis na classe e sub classes.

2.5 Herana

A herana entre uma classe e outra definida pela palavra extends. Pode-se sobrecarregar
mtodos e usar a palavra super para chamar o mtodo da classe pai, conforme o exemplo a
seguir.
TypeScript 31

class Animal {
name:string;
constructor(theName: string) { this.name = theName; }
move(meters: number = 0) {
alert(this.name + " moved " + meters + "m.");
}
}

class Snake extends Animal {


constructor(name: string) { super(name); }
move(meters = 5) {
alert("Slithering...");
super.move(meters);
}
}

class Horse extends Animal {


constructor(name: string) { super(name); }
move(meters = 45) {
alert("Galloping...");
super.move(meters);
}
}

var sam = new Snake("Sammy the Python");


var tom: Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);

Neste exemplo, usamos o super da classe Snake para chamar o mtodo construtor da classe
pai Animal. Se isso no for claro para voc, estude orientao a objetos para que possa
compreender melhor, pois estas caractersticas so da Orientao em Objetos como um todo,
e no do TypeScript.
TypeScript 32

2.6 Accessors (get/set)

Os accessors visam proteger as propriedades de uma classe. Os accessors do TypeScript so


feitos pelas palavras get e set. Veja o exemplo a seguir:

class Pessoa {
private _password: string;

get password(): string {


return this._password;
}

set password(p : string) {


if (p != "123456") {
this._password = p;
}
else {
alert("Ei, senha no pode ser 123456");
}
}
}

var p = new Pessoa();


p.password = "123456"; //exibe o erro

2.7 Mtodos Estticos

possvel criar mtodos estticos definindo a palavra static antes do mtodo. Existem
dezenas de aplicaes para mtodos estticos, sendo uma delas no precisar instanciar uma
classe, como no exemplo a seguir.
TypeScript 33

class SystemAlert{

static alert(message:string):void{
alert(message);
}

static warm (message:string):void{


alert("Ateno: " + message);
}

static error(message:string):void{
alert("Erro: " + message);
}

SystemAlert.alert("Oi");
SystemAlert.error("No foi possvel conectar na base de dados");

2.8 Interfaces

Uma interface define um contrato para a classe. A interface criada da seguinte forma:

interface Point{
x: number;
y: number;
x: number;
}

Para implementar a interface, usamos implements:

class point3d implements Ponto{


//...
}
TypeScript 34

2.9 Funes
Vamos exemplificar algumas particularidades de uma funo em TypeScript. A funo pode
ser criada fora de uma classe ou dentro, sendo as observaes que faremos a seguir podem
ser aplicadas em ambas.

Em uma classe no precisamos usar a palavra function para definir uma funo,
mas fora da classe precisamos.

2.9.1 Valor padro

Pode-se definir um valor padro para um parmetro de uma funo da seguinte forma:

function buildName(firstName: string, lastName : string = "Smith") {


}
// or
class Foo{
buildName(firstName: string, lastName : string = "Smith") {
}
}

2.9.2 Valor opcional

Use o caractere ? para definir um parmetro opcional.

class Foo{
buildName(firstName: string, lastName? : string) {
if (lastName){
// blablabla
}
}
}

2.10 Parmetros Rest

Pode-se repassar um array de valores diretamente para um parmetro. vlido lembrar que
este modo s pode ser usado no ltimo parmetro da sua funo. Exemplo:
TypeScript 35

class Foo{
static alertName(firstName: string, ...restOfName: string[]) {
alert(firstName + " " + restOfName.join(" "));
}
}
Foo.alertName("Fulano","de","Tal");

2.11 Parmetros no formato JSON

Uma das maiores facilidades do Javascript repassar parmetros no formato JSON. Com
TypeScript possvel utilizar este mesmo comportamento, conforme o exemplo a seguir.

class Point{

private _x : number = 0;
private _y : number = 0;
private _z : number = 0;

constructor( p: {x:number;y:number;z?:number;}){
this._x = p.x;
this._y = p.y;
if (p.z)
this._z = p.z;
}

is3d():boolean{
return this._z!=0;
}

var p1 = new Point({x:10,y:20});

alert(p1.is3d()); //false
TypeScript 36

2.12 Mdulos

Na aprendizagem do Angular 2 pode-se escrever cdigo em um nico arquivo, criando vrias


classes em um mesmo bloco de cdigo, mas no desenvolvimento real cada classe da aplicao
deve ser um arquivo TypeScript diferente.
A forma como carregamos os mdulos, classes e arquivos no javascript depende de vrios
fatores, inclusive da escolha de uma biblioteca para tal. Nesta obra, optamos pelo systemjs,
pois a forma utilizada pelo Angular 2.

2.12.1 Exemplo com Systemjs

Vamos criar um novo diretrio chamado testModules, e usar o Visual Studio Code para abrir
este diretrio atravs do menu File > Open Folder. Vamos criar inicialmente dois arquivos
TypeScript chamados de index.ts, que ser o arquivo principal da aplicao, e o arquivo
module.ts que ser um mdulo genrico.

module.ts

export class foo{


getHelloWorldFromModule():string{
return "Hello World from modules";
}
}

A classe foo contm um modificador chamado export, inserido antes do class. Este
modificador diz ao module.ts que a classe poder ser exportada para outras classes da
aplicao. Com o mdulo pronto, criamos o arquivo index.ts, com o seguinte cdigo:

index.js

import {foo} from "module"

var f:foo = new foo();


console.log(f.getHelloWorldFromModule());

Na primeira linha do arquivo index.ts usamos a diretiva import para importar a classe
foo do mdulo module. Nesta sintaxe, o que inserido entre chaves so as classes a serem
TypeScript 37

importadas, e o aps a palavra from inserimos o nome do arquivo do mdulo. Como o arquivo
module.js, usamos module.
Neste primeiro momento ainda no temos as configuraes necessrias para que o Visual
Studio Code compreenda o cdigo TypeScript apresentado e possivelmente sua tela ser
semelhante imagem a seguir:

Perceba o erro em module, pois o editor Visual Studio Code no foi capaz de encontra o
mdulo. Na verdade o VSCode ainda nem conseguiu determinar a forma de carregamento
de mdulos utilizada. Conforme foi visto anteriormente, necessrio criar o arquivo
tsconfig.json com estas configuraes, de acordo com o cdigo a seguir:

tsconfig.json

{
"compilerOptions": {
"target": "es6",
"module": "system",
"sourceMap": true
},
"files": [
"index.ts"
]
}

O arquivo de configurao do TypeScript indica atravs da propriedade module qual ser


TypeScript 38

a estratgia de carregamento de arquivos. Neste caso usaremos system. SourceMap tambm


est habilitado para a gerao dos arquivos .map com o objetivo de auxiliar o Debug. Tambm
inclumos a propriedade files que configura quais os arquivos sero compilados para
JavaScript. Se omitirmos a propriedade files, todos os arquivos do diretrio testModules
sero compilados. Como fornecemos apenas o arquivo index.ts, ele ser compilado primeiro,
e outros sero compilados se, e somente se, forem importados.
Relembrando a importncia do arquivo tsconfig.json, ele auxilia o comando tsc que foi
instalado no sistema atravs do npm. Isso significa que se executarmos tsc na linha de
comando, dentro da pasta testModules, tudo ser compilado, conforme a imagem a seguir:

Mas no o nosso objetivo abrir um terminar e executar o comando tsc a todo o


momento que queremos compilar o projeto. Para isso iremos configurar uma tarefa (task)
no Visual Studio Code. No VSCode, aperte F1 e digite Configre Task Runner. O arquivo
.vscode/tasks.json ser criado com diversas opes. Reduza o arquivo para a seguinte
configurao json:

.vscode/tasks.json

{
"version": "0.1.0",
"command": "tsc",
"isShellCommand": true,
"showOutput": "silent",
"problemMatcher": "$tsc"
}

Esta configurao ir executar o comando tsc com as opes do config.json.


TypeScript 39

No inclua no arquivo tasks.json a propriedade args, pois se isso for feito, o


arquivo tsconfig.json ser completamente ignorado.

Com a task configurada, basta pressionar ctrl+shift+b para executar a tarefa. Os arquivos
js e js.map sero criados, e o erro inicial no module no acontecer novamente.

2.12.2 Omitindo arquivos js e map no VSCode

Aps a compilao inicial, a interface do Visual Studio Code deve ser semelhante imagem
a seguir:

Perceba que a relao de arquivos est um pouco confusa pois existem trs arquivos
semelhantes, como por exemplo: index.js, index.ts e index.js.map. Os arquivos js e map
so os arquivos compilados do TypeScript, e no h a necessidade que eles apaream na lista
de arquivos do editor.
Para resolver este problema, acesse File > Preferences > User Settings, onde o arquivo
global de preferncias do usurio ser aberto. Para que possamos omitir os arquivos js e map
do editor, devemos configurar a propriedade files.exlude, conforme o cdigo a seguir:
TypeScript 40

"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
"**/node_modules": true,
"**/*.js": { "when": "$(basename).ts"},
"**/*.js.map": true
}

Neste exemplo, as pastas .git, .DS_Store, node_modules sero omitidas. Na penltima con-
figurao: "**/*.js": { "when": "$(basename).ts"} estamos omitindo todos os arquivos
com a extenso .js que possuem o seu correspondente .ts e na ltima configurao estamos
omitindo todos os arquivos com a extenso .js.map.
Aps inserir estas informaes, o VSCode fica semelhante figura a seguir:

2.12.3 Uso do SystemJS

Agora que j criamos e compilamos os arquivos TypeScript preciso test-los no navegador.


Para isso deve-se criar o arquivo index.html e inserir a biblioteca SystemJS, que deve ser
obtida atravs do npm.
TypeScript 41

Inicialmente vamos inicializar o npm no diretrio atravs do comando npm init, conforme
a imagem a seguir:

Com o arquivo package.json criado, possvel adicionar a biblioteca systemjs, atravs do


seguinte comando:

$ npm i systemjs -S

Como esperado o diretrio node_modules ser criado e o systemjs ser adicionado ela,
conforme a figura a seguir:
TypeScript 42

Com a biblioteca systemjs pronta, podemos criar o arquivo index.html, com o seguinte
contedo:

index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Module Test</title>
<script src="node_modules/systemjs/dist/system.js"></script>
<script>
System.defaultJSExtensions = true;
System.import('index');
</script>
</head>
<body>
</body>
</html>

O arquivo index.html contm a incluso da biblioteca system.js, instalada previamente pelo


npm. Aps incluir system.js no documento html, adicionamos System.defaultJSExtensions
= true para habilitar a extenso automtica dos arquivos, e System.import('index') para
importar o arquivo index.js.
TypeScript 43

O arquivo index.js, por sua vez, importa o arquivo modules.js. Este procedimento pode ser
analisado no Google Chrome (aperte F12 aps carregar a pgina), na aba Network, conforme
a figura a seguir:

Para habilitar o Debug no Google Chrome, navegue at a aba Sources, selecione o arquivo
TypeScript que deseja debugar, e adicione um breakpoint, conforme a figura a seguir:
TypeScript 44

Para acessar o arquivo index.html no navegador, use o live-


server que foi instalado globalmente. Basta acessar o diretrio
testModules e digitar live-server, conforme a figura a seguir:

2.13 Decorators (ou annotation)

Decorators so amplamente usados em linguagens de programao. Sua principal funci-


onalidade configurar uma classe/varivel/mtodo atravs de propriedades. Em algumas
linguagens um decorator chamado de annotation.
Por exemplo, a biblioteca Hibernate do Java usa decorators para configurar uma classe que
representa uma tabela, como no exemplo a seguir:
TypeScript 45

import javax.persistence.*;

@Table(name = "EMPLOYEE")
public class Employee {
@Id @GeneratedValue
@Column(name = "id")
private int id;
}

No exemplo acima, temos o decorator @Table com a propriedade name=="EMPLOYEE". O


campo id tambm tem o decorator @id e @Column, configurando o campo da tabela. O mesmo
pode ser aplicado no C#, como no exemplo a seguir:

public class Product


{
[Display(Name="Product Number")]
[Range(0, 5000)]
public int ProductID { get; set; }
}

E finalmente o mesmo pode ser aplicado no TypeScript, e amplamente utilizado no Angular


2. Um exemplo de decorator no Angular 2 apresentado a seguir:

import {Component} from '@angular/core'

@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

O uso do @Component antes da classe AppComponent um decorator do Angular 2. Neste


exemplo, o uso do @Component transforma a classe AppComponent em um componente do
Angular, e com duas propriedades definidas: selector e template.
No o foco desta obra aprender a criar um decorator, mas sim us-los. Uma caracterstica
importante que deve-se saber sobre os decorators em TypeScript que o arquivo tscon-
fig.json deve incluir duas novas informaes: emitDecoratorMetadata e experimentalDe-
corators, como ser visto no prximo captulo.
TypeScript 46

2.14 Concluso

Neste captulo tivemos uma ampla abordagem ao TypeScript, que a linguagem que pode ser
usada no Angular 2. O TypeScript est ganhando mercado por trazer uma alternativa mais
slida ao desenvolvimento JavaScript, prova disso o prprio framework Angular 2. Tambm
vimos o Visual Studio Code que um editor de textos muito poderoso e com ferramentas na
medida certa para o desenvolvimento JavaScript.
3. Um pouco de prtica
Neste capitulo iremos introduzir alguns conceitos sobre o Angular 2. A primeira tarefa ser
criar um projeto bsico, no qual poderemos Copiar/Colar para criar novos projetos.

3.1 Projeto AngularBase

Inicialmente criaremos um projeto bsico para que possamos, a qualquer momento, copiar e
colar para um novo projeto.

3.1.1 Configurando o projeto

Crie a pasta AngularBase e, pela linha de comando, configure o arquivo package.json atravs
do npm:

$ npm init
...(configure as opes)...

Adicione as dependncias do Angular 2 ao projeto, editando o arquivo packaje.json:

package.json

{
"name": "angularbase",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@angular/common": "2.0.0",
"@angular/compiler": "2.0.0",
"@angular/core": "2.0.0",
"@angular/forms": "2.0.0",
"@angular/http": "2.0.0",
"@angular/platform-browser": "2.0.0",
"@angular/platform-browser-dynamic": "2.0.0",
Um pouco de prtica 48

"@angular/router": "3.0.0",
"@angular/upgrade": "2.0.0",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.12",
"systemjs": "0.19.27",
"zone.js": "^0.6.23",
"angular2-in-memory-web-api": "0.0.20",
"bootstrap": "^3.3.6"
}
}

Execute npm install para que as bibliotecas sejam instaladas.

3.1.2 Configurando a compilao do TypeScript

Abra o diretrio AngularBase no Visual Studio Code e crie o arquivo tsconfig.json. Como
visto no capitulo anterior, o arquivo tsconfig.json conter informaes de compilao do
TypeScript para o javaScript. O contedo deste arquivo :

tsconfig.json

{
"compilerOptions": {
"target": "es6",
"module": "system",
"sourceMap": true,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"exclude": [
"node_modules"
]
}
Um pouco de prtica 49

Esta configurao apresenta alguns detalhes extras em relao s configuraes anteriores.


Em moduleResolution definido a estratgia de carregamento dos mdulos, neste caso
node. Desta forma, podemos carregar mdulos do diretrio node_modules. As configuraes
emitDecoratorMetadata e experimentalDecorators habilitam o uso de decorators. Como
o Angular 2 usa-os extensivamente, necessrio ativ-las. Em noImplicitAny iremos
desabilitar a mensagem de erro para algum mtodo ou propriedade sem um tipo definido.
J exclude ir excluir a compilao de qualquer arquivo TypeScript que estiver no diretrio
node_modules.

Para configurar a tarefa (task) que ir compilar o TypeScript, pressione ctrl+shift+b (Se
estiver utilizando o Visual Studio Code) e caso ainda no exista, crie-a clicando em Configure
Task Runner e escolha Typescript - tsconfig.json

O arquivo .vscode/tasks.json conter a seguinte configurao:

.vscode/tasks.json

{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"command": "tsc",
"isShellCommand": true,
"showOutput": "silent",
"problemMatcher": "$tsc"
}
Um pouco de prtica 50

Se estiver utilizando outro editor de textos, ao invs de configurar uma task, abra
o terminal, navegue at o diretrio e digite: tsc

3.1.3 Criando o primeiro componente Angular 2

At o momento nenhum arquivo TypeScript foi criado, ento ainda no h o que compilar.
O Angular 2 focado na criao de componentes, ento ao invs de adicionarmos cdigo
html ou javascript para construir a aplicao, vamos focar na criao e manipulao de
componentes.
Como conveno, vamos criar o diretrio app, que onde os componentes ficaro. Cada
componente ter a extenso .component.ts, e o primeiro componente a ser criado o que
define a aplicao. Neste caso, criaremos o arquivo app/app.component.ts com o seguinte
cdigo:

app/app.component.ts

import {Component} from '@angular/core'

@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

Na primeira linha, usamos o comando import para importar a classe Component, diretamente
do Angular. Perceba que @angular/core est definido em node_modules/@angular/core.
Aps o import, possvel usar o decorator @Component e repassar dois parmetros: selector
e template. O parmetro selector define qual a tag ser usada para a instanciao
do componente na pgina html. Com o valor my-app, subtende-se que ao usarmos <my-
app></my-app> o componente ser carregado. J template define o cdigo html que ser
usado como template no componente.
Aps o decorator @Component ser criado podemos criar a classe AppComponent, que usa o
export para dizer que a classe publica ao mdulo.
Um pouco de prtica 51

3.1.4 Criando o mdulo

A princpio, o aplicao possuir um mdulo principal. Crie o arquivo app/app.module.ts


com o seguinte cdigo:

app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }

3.1.5 Criando o bootstrap

O bootstrap responsvel em inicializar o Angular 2, atravs do mdulo principal:

app/boot.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

Na primeira linha do arquivo app/boot.ts importamos o mtodo bootstrap de @angular/platform-


browser-dynamic. Na segunda linha, importamos o componente AppComponent. Perceba que
o caminho usado no from ./app.component, onde o ./ indica a raiz do arquivo, neste caso
app. Aps os imports, chamamos o mtodo bootstrap(AppComponent); que ir inicializar a
aplicao Angular.

3.1.6 Criando o arquivo html

Para finalizar o projeto base, precisamos criar o html que conter a aplicao. Crie o arquivo
index.html na pasta AngularBase com o seguinte cdigo:
Um pouco de prtica 52

index.html

<html>
<head>
<title>Angular Base</title>
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>

Ateno Em alguns cdigos do arquivo PDF voc ver o fim de uma linha com
uma contra barra \. Isso indica que a linha no acabou, e continua na linha
seguinte. Se voc for copiar e colar o cdigo, retire a contra barra do cdigo
tambm. Neste exemplo, ao invs de </scri\pt>, o correto seria </script>

Este arquivo html pode ser separado em trs blocos. O primeiro contm o carregamento das
bibliotecas padro do Angular 2, juntamente com o SystemJS que foi abordado no captulo
anterior. Depois adicionarmos systemjs.config.js que configura o SystemJS. O comando
System.import ir importar app que o arquivo de bootstrap que criamos. A partir do app
outras classes sero criadas. . Na tag <body> temos a criao da tag <my-app></my-app> onde
a aplicao ser renderizada.
O arquivo systemjs.config.js exibido a seguir:
Um pouco de prtica 53

systemjs.config.js

/**
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/pl\
atform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dy\
namic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
},
// packages tells the System loader how to load when no filename and/or \
no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
Um pouco de prtica 54

rxjs: {
defaultExtension: 'js'
},
'angular2-in-memory-web-api': {
main: './index.js',
defaultExtension: 'js'
}
}
});
})(this);

Este arquivo possui informaes sobre o carregamento de mdulos do Angular (e outras


bibliotecas) pelo SystemJS.
Para testar o projeto, recompile-o com ctrl+shit+b no Visual Studio Code (ou digite tsc no
terminal, no diretrio AngularBase) e use o live-server para iniciar o servidor web.
Com o projeto finalizado, pode-se us-lo para copiar e colar em um novo projeto (Copiar a
pasta e colar em uma nova pasta com outro nome).

3.2 Criando uma pequena playlist

O foco desta obra apresentar o Angular 2 atravs de exemplos, na prtica. Ao invs


de exibir a teoria sobre os mais diferentes aspectos do Angular 2, tais como templates,
components, diretivas, metadata, databind, injeo de dependncia, entre outros, vamos criar
uma aplicao funcional e explicar a teoria somente no prximo captulo.
Nossa prxima aplicao uma playlist, pode ser de vdeos contendo o ttulo, a url e uma
descrio. A princpio a playlist mostra somente o ttulo, e quando o usurio clicar no item
da lista, poder acessar a Url e a descrio. Tambm pode-se editar e criar novos vdeos, mas
ao atualizar a pgina estas modificaes sero perdidas, pois em um primeiro momento no
estaremos comunicando com o servidor ou com o banco de dados.
Resultado final da playlist:
Um pouco de prtica 55

3.2.1 Estrutura inicial dos arquivos

Copie o diretrio AngularBase e cole como AngularPlaylist. Verifique se a pasta node_-


modules contm as bibliotecas do angular. Em caso negativo, execute o comando npm install
para atualizar estas bibliotecas.
Abra o diretrio AngularPlaylist no Visual Studio Code. A primeira alterao que devemos
fazer adicionar a propriedade watch:true no arquivo tsconfig.json, desta forma, toda vez
que um arquivo for alterado o TypeScript ir recompilar o projeto. Pressione ctrl+shift+b
para recompilar o projeto (e deixar o watcher recompilar as prximas alteraes), e execute
o live-server no terminal para que a pgina index.html seja aberta. A pgina ser aberta
com o texto My First Angular 2 App.
O mdulo principal do projeto deve possuir uma referncia ao mdulo do angular res-
ponsvel em gerenciar campos de formulrios, chamado de FormModule. Altere o arquivo
app\app.module.ts para:
Um pouco de prtica 56

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


import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
imports: [
BrowserModule,
FormsModule
],
declarations: [
AppComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }

Para testar se o TypeScript est funcionando juntamente com o live-server, abra o arquivo
app/app.component.ts e altere o template do componente para:

app/app.component.ts

import {Component} from '@angular/core'

@Component({
selector: 'my-app',
template: '<h1>My Playlist</h1>'
})
export class AppComponent { }

O live-server ir recarregar a pgina com a nova informao do template.

3.2.2 Criando um arquivo de configurao da aplicao

Nesta primeira etapa exibiremos como repassar variveis estticas entre as classes da
aplicao. Chamamos de Service uma classe comum com o propsito de servir outra classe.
Neste caso, criaremos o arquivo app/config.service.ts com o seguinte cdigo:
Um pouco de prtica 57

app/config.service.ts

export class Config{


/**
* Ttulo da pgina da aplicao
*/
static TITLE_PAGE : string = "My Playlist";
}

A classe Config possui inicialmente a varivel TITLE_PAGE que esttica e possui o valor My
Playlist. Para podermos usar esta varivel no componente App, precisamos primeiro alterar
o arquivo app.component.ts para:

app/app.component.ts

import {Component} from '@angular/core'

@Component({
selector: 'my-app',
template: '<h1>{{title}}</h1>'
})
export class AppComponent {
title = "My Playlist";
}

Ou seja, estamos no template usando um recurso chamado Databind, e atravs de {{ }} po-


demos referenciar uma varivel da classe. O valor da varivel title da classe AppComponent
ser atribuda ao {{title}} do template. Existem muitos tipos de databind que veremos ao
longo desta obra.
Agora precisamos ligar a varivel title da classe AppComponent a varivel TITLE_PAGE da
classe Config. Para isso, basta importar a classe e us-la. Como a varivel esttica, o ttulo
da pgina acessado diretamente pela classe, sem a necessidade de instanciar a classe Config.
Um pouco de prtica 58

app/app.component.ts
import {Component} from '@angular/core'
import {Config} from './config.service'

@Component({
selector: 'my-app',
template: '<h1>{{title}}</h1>'
})
export class AppComponent {
title = Config.TITLE_PAGE;
}

Veja que o editor de textos (Visual Studio Code) pode lhe ajudar com a complementao de
cdigo:

3.2.3 Adicionando bootstrap

Para que a aplicao comece a ganhar uma boa forma visual, precisamos estilizar a aplicao
com CSS,e uma das formas de fazer isso utilizando o bootstrap. No terminal, adicione a
biblioteca bootstrap atravs do seguinte comando:
Um pouco de prtica 59

$ npm i bootstrap -S

O diretrio node_modules/bootstrap ser adicionado, e podemos incluir a folha de estilos


no arquivo index.html:

index.html

<html>
<head>
<title>Angular Playlist</title>
<base href="/">
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min\
.css">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<div class="container">
<my-app>Loading...</my-app>
</div>
</body>
</html>

Na alterao do arquivo index.html, adicionamos a folha de estilos bootstrap.min.css,


alm de criar uma div com a classe container, adicionando uma margem na pgina da
aplicao. Outra modificao foi no arquivo app.component.ts, onde adicionamos uma
classe css para o ttulo:
Um pouco de prtica 60

app/app.component.ts

import {Component} from '@angular/core'


import {Config} from './config.service'

@Component({
selector: 'my-app',
template: '<h1 class="jumbotron">{{title}}</h1>'
})
export class AppComponent {
title = Config.TITLE_PAGE;
}

Ao adicionarmos class="jumbotron" no <h1> do componente, temos a aplicao sendo


exibida da seguinte forma:

3.2.4 Criando a classe Video

Como a Playlist sobre vdeos, natural pensarmos em criar uma classe que representa
um vdeo, contendo ttulo, url e descrio. Esta classe se chamar video.ts, com o seguinte
cdigo:
Um pouco de prtica 61

app/video.ts

export class Video{


id:number;
title:string;
url:string;
desc:string;
constructor(id:number,title:string,url:string,desc?:string){
this.id=id;
this.title=title;
this.url=url;
this.desc=desc;
}
}

3.2.5 Criando uma lista simples de vdeos

Com a classe Video criada, podemos criar uma lista contendo os vdeos. Esta lista composta
de um array com os dados, de uma classe e um template. Primeiro, criamos o array com os
dados, que inicialmente ser fixo (no h comunicao com o servidor):

import {Component} from '@angular/core'


import {Config} from './config.service'
import {Video} from './video'

@Component({
selector: 'my-app',
template: '<h1 class="jumbotron">{{title}}</h1>'
})
export class AppComponent {
title = Config.TITLE_PAGE;
videos : Array<Video>;

constructor(){
this.videos = [
new Video(1,"Test","www.test.com","Test Description"),
new Video(2,"Test 2","www.test2.com")
Um pouco de prtica 62

]
}
}

Perceba que voltamos ao app.component, importamos a classe Video e criamos a varivel


videos. No construtor da classe app.component preenchemos o array com 2 vdeos. vlido
lembrar que para acessar o servidor web e obter dados a estratgia ser outra, mas vamos
simplificar esta parte inicialmente, para que possamos compreender o funcionamento dos
componentes no Angular 2.

3.2.6 Criando sub-componentes

Para que possamos exibir esta lista de vdeos, podemos inserir <ul> e <li> no template do
AppComponent (onde o <h1> foi criado), mas esta no uma boa prtica, j que devemos
sempre quebrar a aplicao em componentes.

Quebrar uma aplicao em diversos componentes uma boa prtica no Angular


2, respeitando inclusive o princpio da responsabilidade nica. Estes princpios
se aplicam a qualquer linguagem de programao, acesse este link para maiores
detalhes.

Para uma lista de vdeos, podemos criar o componente VideoListComponent. Crie o arquivo
app/videolist.component.ts com o seguinte cdigo inicial:

import {Component} from '@angular/core'


@Component({
selector: 'video-list',
templateUrl: 'app/videolist.component.html'
})
export class VideoListComponent {

Nesta classe usamos a propriedade templateUrl ao invs de template, apenas para demons-
trar que podemos ter um arquivo html de template separado do componente, o que uma
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
Um pouco de prtica 63

boa prtica de programao para o Angular 2. O caminho para o template deve ser completo
a partir da base da aplicao, por isso o app/ foi inserido. Nada impede de criar um diretrio
chamado templates na raiz da aplicao, ou dentro do diretrio app.

Uma outra boa prtica de programao separar cada componente em diret-


rios, principalmente em projetos com muitos componentes. Como exemplo o
componente VideoList estaria no diretrio app/components/video, onde este
diretrio teria os componentes relativos a informaes sobre os vdeos (Lista
de vdeos, tela de edio e visualizao). O template para VideoList estaria em
app/components/video/templates.

Crie o template do componente VideoList, que a princpio possui somente uma mensagem
simples:

app/videolist.component.html
<b> Video List Component </b>

Aps criar o componente e o template, podemos inser-lo na aplicao principal AppCom-


ponent:

app/app.component.ts
import {Component} from '@angular/core'
import {Config} from './config.service'
import {Video} from './video'
@Component({
selector: 'my-app',
template: '<h1 class="jumbotron">{{title}}</h1><video-list></video-list>',
})
export class AppComponent {
...
}

Inserimos <video-list> no final do template. Se for realizado um teste agora, o componente


no ser exibido. Isso acontece porque somente o <video-list> no faz com que o Angular
carregue o componente VideoListComponent. preciso informar ao Angular para carregar
o componente, e isso feito atravs da propriedade declarations que deve ser inserida no
mdulo principal, veja:
Um pouco de prtica 64

app/app.module.ts

1 import { NgModule } from '@angular/core';


2 import { BrowserModule } from '@angular/platform-browser';
3 import { FormsModule } from '@angular/forms';
4 import { AppComponent } from './app.component';
5 import {VideoListComponent} from './videolist.component'
6 import {VideoDetailComponent} from './videodetail.component'
7
8 @NgModule({
9 imports: [
10 BrowserModule,
11 FormsModule
12 ],
13 declarations: [
14 AppComponent,VideoListComponent,VideoDetailComponent
15 ],
16 bootstrap: [ AppComponent ]
17 })
18 export class AppModule { }

3.2.7 Formatando o template

O template do AppComponent est descrito em uma linha nica, o que pode gerar confuso j
que o cdigo html pode ser extenso. Existem duas alternativas para resolver este problema.
A primeira usar o template com vrias linhas, usando o caractere acento grave ` ao invs
do apstrofo como delimitador, como no exemplo a seguir:

app/app.component.ts

import {Component} from '@angular/core'


import {Config} from './config.service'
import {Video} from './video'
import {VideoListComponent} from './videolist.component'

@Component({
selector: 'my-app',
template: `
Um pouco de prtica 65

<h1 class="jumbotron">
{{title}}
</h1>
<video-list></video-list>
`
})
export class AppComponent {
...
}

Pode-se tambm utilizar a propriedade templateUrl ao invs do template, repassando assim


a url do arquivo html do template, conforme o exemplo a seguir:

app/app.component.ts

import {Component} from '@angular/core'


import {Config} from './config.service'
import {Video} from './video'
import {VideoListComponent} from './videolist.component'

@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
...
}

app/app.component.html

<h1 class="jumbotron">
{{title}}
</h1>
<video-list></video-list>

Aps criar o template do AppComponent, podemos testar a aplicao, que deve ter a interface
semelhante a figura a seguir:
Um pouco de prtica 66

3.2.8 Repassando valores entre componentes

Criamos a varivel videos no AppComponent, com dois itens. Para repassar este array ao
componente VideoList, usamos o conceito de binding do Angular 2. Para repassar um valor
de um componente para outro, deve-se criar uma propriedade no seletor do componente
utilizando colchetes, como no exemplo a seguir:

app/app.component.html

<h1 class="jumbotron">
{{title}}
</h1>
<video-list [videos]="videos"></video-list>

Ao adicionarmos [videos]="videos", dizemos que a varivel [videos] do VideoListCom-


ponent igual ao valor da varivel videos do AppComponent (que o array preenchido no
seu construtor). Para criar a varivel videos no componente VideoListComponent, usamos a
propriedade inputs na configurao do @Component, veja:
Um pouco de prtica 67

app/videolist.component.ts

import {Component} from '@angular/core'


@Component({
selector: 'video-list',
templateUrl: 'app/videolist.component.html',
inputs: ['videos']
})
export class VideoListComponent {

Outra alternativa criar a varivel videos na classe e usar o metadata @input, por exemplo:

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


@Component({
selector: 'video-list',
templateUrl: 'app/videolist.component.html'
})
export class VideoListComponent {
@input() videos;
}

Como o componente VideoListComponent tem a propriedade videos, pode-se alterar o


template para usar esta varivel. A princpio, podemos alterar o template para:

Videos: {{videos.length}}

Usamos o databind {{videos.length}} para retornar a quantidade de itens da varivel


videos. Como no construtor de AppComponent foram criados 2 vdeos, o valor ser 2,
conforme a imagem a seguir:
Um pouco de prtica 68

Ao invs de exibirmos a quantidade de itens do array, vamos alterar o template para desenhar
uma tabela com a ajuda do bootstrap:

<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let v of videos">
<td>{{v.id}}</td>
<td>{{v.title}}</td>
</tr>
</tbody>
</table>

Para exibir a lista de videos, usamos a diretiva *ngFor no qual o asterisco indica que a tag
li faz parte de um elemento mestre/detalhe, ou seja, ela vai se repetir de acordo com a
Um pouco de prtica 69

quantidade de itens. O loop feito de acordo com let v of videos, o que significa que cada
item do array videos vai ser armazenado na varivel v. A tralha usada antes da varivel
v indica que ela poder ser usada como uma varivel dentro do loop. Neste caso, usamos
{{v.id}} e {{v.title}}.

O resultado com o novo template utilizando o *ngFor apresentado a seguir:

3.2.9 Selecionando um vdeo

Vamos adicionar a funcionalidade de selecionar o vdeo da lista de vdeos. Quando seleciona


uma linha da tabela, mostramos o componente VideoComponent, que possui uma chamada
para o vdeo e trs campos de texto contendo o ttulo, url e descrio do mesmo.

3.2.10 Eventos

Para adicionar um evento ao <li> que foi gerado, usamos a diretiva (click), da seguinte
forma:
Um pouco de prtica 70

<table class="table table-hover">


<thead>
<tr>
<th>ID</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let v of videos" (click)="onSelect(v)">
<td>{{v.id}}</td>
<td>{{v.title}}</td>
</tr>
</tbody>
</table>

O mtodo onSelect ser executado no VideoListComponent, no qual a princpio podemos


apenas emitir um alert para teste:

import {Component} from '@angular/core'


import {Video} from './video'

@Component({
selector: 'video-list',
templateUrl: 'app/videolist.component.html',
inputs: ['videos']
})
export class VideoListComponent {
onSelect(vid: Video) {
console.log(JSON.stringify(vid));
}
}

Na classe VideoListComponent criamos o mtodo onSelect com a propriedade vid, que


do tipo Video (inclua o import tambm). Por enquanto, o mtodo apenas usa o alert para
exibir os dados do vdeo selecionado, semelhante a figura a seguir:
Um pouco de prtica 71

3.2.11 Propagando eventos

Quando o usurio clica em um vdeo, deve-se informar ao AppComponent que este evento
ocorreu. O componente VideoListComponent no pode chamar diretamente um mtodo do
AppComponent, isso uma m prtica de programao. O componente VideoListComponent
deve disparar um evento que vai propagar at o componente AppComponent.
Primeiro vamos criar o evento no componente VideoListComponent:

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


import {Video} from './video'

@Component({
selector: 'video-list',
templateUrl: 'app/videolist.component.html',
inputs: ['videos'],
outputs: ['selectVideo']
})
export class VideoListComponent {
selectVideo = new EventEmitter();

onSelect(vid: Video) {
this.selectVideo.next(vid);
Um pouco de prtica 72

}
}

Ao invs de outputs: ['selectVideo'] no @Component, pode-se usar direta-


mente @output() selectVideo = new EventEmitter()

Perceba que adicionamos no import a classe EventEmitter. Tambm adicionamos uma nova
diretiva ao @Component que o outputs, indicando que SelectVideo um evento de sada do
componente. No mtodo onSelect, ao invs do console.log usamos a varivel selectVideo
para disparar o evento, atravs do mtodo next, repassando o vdeo que o usurio selecionou
no evento.
Com o VideoListComponent disparando o evento, podemos voltar ao AppComponent para
captur-lo. Isso ser realizado em duas etapas. Primeiro, no template:

<h1 class="jumbotron">
{{title}}
</h1>
<video-list [videos]="videos"
(selectVideo)="onSelectVideo($event)">
</video-list>

No template usamos o evento (selectVideo) chamando o callback onSelectVideo, e repas-


sando $event. Agora precisamos criar o mtodo onSelectVideo na classe AppComponent:

import {Component} from '@angular/core'


import {Config} from './config.service'
import {Video} from './video'
import {VideoListComponent} from './videolist.component'

@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
title = Config.TITLE_PAGE;
Um pouco de prtica 73

videos : Array<Video>;

constructor(){
this.videos = [
new Video(1,"Test","www.test.com","Test Description"),
new Video(2,"Test 2","www.test2.com","Test Description")
]
}

onSelectVideo(video){
console.log(JSON.stringify(video));
}
}

O resultado at agora o mesmo em termos de interface, mas agora o vdeo selecionado


pelo usurio est na classe AppComponent, que a classe que controla toda a aplicao. O
componente VideoListComponent cumpre apenas o papel de mostrar os vdeos e disparar
eventos caso um dos itens seja selecionado.

Nos tempaltes, usamos [ ] para repassar variveis ao componente, e usamos ( )


para indicar eventos.

3.2.12 Exibindo os detalhes do vdeo

Vamos criar um novo componente, chamado VideoDetailComponent, que a princpio exibe


apenas o titulo do vdeo:
Um pouco de prtica 74

app/videodetail.component.ts

import {Component} from '@angular/core'


import {Video} from './video'

@Component({
selector:'video-detail',
templateUrl: 'app/videodetail.component.html',
inputs: ['video']
})
export class VideoDetailComponent{

A casse VideoDetailComponent possui o seletor video-detail, o template videodetail.component.html


e inputs:['video'] que ser a propriedade que representa o vdeo selecionado.
Neste momento, o template possui apenas a informao do ttulo do livro:

app/videodetail.component.html

<h2>{{video.title}}</h2>

Agora alteramos a aplicao principal, AppComponent, onde criaremos uma propriedade


chamada selectedVideo, que ir controlar o vdeo selecionado pelo evento do VideoList-
Component, veja:

import {Component} from '@angular/core'


import {Config} from './config.service'
import {Video} from './video'
import {VideoListComponent} from './videolist.component'

@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
title = Config.TITLE_PAGE;
Um pouco de prtica 75

videos : Array<Video>;
selectedVideo: Video;

constructor(){
this.videos = [
new Video(1,"Test","www.test.com","Test Description"),
new Video(2,"Test 2","www.test2.com","Test Description")
]
}

onSelectVideo(video){
//console.log(JSON.stringify(video));
this.selectedVideo = video;
}
}

Com a propriedade selectedVideo preenchida, podemos controlar a visualizao do compo-


nente VideoDetailComponent, atravs do template da aplicao:

app/app.component.html

<h1 class="jumbotron">
{{title}}
</h1>

<video-list [videos]="videos"
(selectVideo)="onSelectVideo($event)">
</video-list>

<video-detail
*ngIf="selectedVideo"
[video]="selectedVideo">
</video-detail>

Neste template, temos a incluso do <video-detail>. Usamos a diretiva *ngIf para controlar
se o componente exibido ou no na pgina. O asterisco necessrio para indicar ao angular
que este controle ir alterar a DOM de alguma forma. Tanto ngIf e ngFor possuem esta
caracterstica.
Um pouco de prtica 76

Em [video]="selectedVideo" temos a propriedade video do VideoComponentDetail rece-


bendo o valor de selectedVideo do componente AppComponent.
Podemos testar a aplicao e clicar nas linhas da tabela de vdeos para que o componente
VideoDetail seja exibido, conforme a figura a seguir:

3.2.13 Editando os dados do video selecionado

Agora vamos alterar o template do VideoDetailtComponent para algo mais agradvel. O


desenho a seguir ilustra como a tela dever ser desenhada:
Um pouco de prtica 77

Para implementar esta tela, usaremos alguns conceitos do Bootstrap, a biblioteca css que
estiliza a aplicao. Tambm usaremos a diretiva [(model)]="field" que implementa o
Databind entre o campo de texto e o valor da propriedade.

veideodetail.component.html
<div class="row">
<div class="col-md-4">

</div>
<div class="col-md-8">
<form>
<h3>{{video.title}}</h3>
<div class="form-group">
<input type="input"
class="form-control"
id="url"
required
Um pouco de prtica 78

placeholder="url"
[(ngModel)]="video.url"
>
</div>
<div class="form-group">
<textarea class="form-control" rows="5" [(ngModel)]="video.desc">
</textarea>
</div>
<button type="button"
class="btn btn-default"
(click)="onButtonOkClick()"
>Ok</button>
</form>
</div>
</div>

Neste formulrio os campos url e desc esto relacionados ao modelo atravs do recurso de
databind do angular, provido pelo uso do [()]. Este recurso chamado de Two Way DataBind
pois ao alterar o valor da caixa de texto, o mesmo alterado na propriedade selectedVideo,
que por sua vez altera o array de vdeos.
O resultado at este momento exibido a seguir:
Um pouco de prtica 79

3.2.14 Editando o ttulo

Um recurso simples que podemos adotar usar o evento (click) no ttulo do formulrio
para que o mesmo seja alterado do <h3> para o <input>. Para controlar este efeito, deve-se
criar o campo do ttulo e adicionar uma varivel no componente VideoDetailComponent, da
seguinte forma:

veideodetail.component.html

<div class="row">
<div class="col-md-4">

</div>
<div class="col-md-8">
<form>
<h3 *ngIf="!editTitle" (click)="onTitleClick()">
{{video.title}}</h3>
<div *ngIf="editTitle" class="form-group">
Um pouco de prtica 80

<input type="input"
class="form-control"
id="title"
required
placeholder="title"
[(ngModel)]="video.title"
>
</div>
<div class="form-group">
<input type="input"
class="form-control"
id="url"
required
placeholder="url"
[(ngModel)]="video.url"
>
</div>
</form>
</div>
</div>

A varivel editTitle ir controlar qual elemento estar visvel. Por padro, o elemento <h3>
aparece primeiro, e se o usurio clicar no elemento, o evento onTitleClick ser disparado.
No componente, temos:

videodetail.component.ts

import {Component} from '@angular/core'


import {Video} from './video'

@Component({
selector:'video-detail',
templateUrl: 'app/videodetail.component.html',
inputs: ['video']
})
export class VideoDetailComponent{
private editTitle:boolean = false;
onTitleClick(){
Um pouco de prtica 81

this.editTitle=true;
}
onButtonOkClick(){
//todo
}
ngOnChanges(){
this.editTitle=false;
}
}

No componente, quando onTitleClick executado, alteramos o valor da propriedade edit-


Table, e desta forma o <h3> escondido e o campo <input> do ttulo aparece. Adicionamos
tambm o evento ngOnChanges que executado sempre que os dados do componente alteram,
ou seja, quando a propriedade video alterada, o evento ser disparado e a varivel
editTitle retorna para false.

A ltima implementao do componente o boto Ok, que deve fechar o formulrio. Na


verdade, o boto Ok vai disparar o evento close e a aplicao ir tratar o evento.

videodetail.component.ts

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


import {Video} from './video'

@Component({
selector:'video-detail',
templateUrl: 'app/videodetail.component.html',
inputs: ['video'],
outputs: ['closeForm']
})
export class VideoDetailComponent{
private closeForm = new EventEmitter();
private editTitle:boolean = false;
onTitleClick(){
this.editTitle=true;
}
onButtonOkClick(){
this.closeForm.next({});
}
Um pouco de prtica 82

ngOnChanges(){
this.editTitle=false;
}
}

Para adicionar o evento, importamos a classe EventEmitter e criamos o evento chamado


closeForm. No mtodo onButtonOkClick, o evento disparado.

No AppComponent adicionamos o evento no template:

<video-detail
*ngIf="selectedVideo"
[video]="selectedVideo"
(closeForm)="onCloseDetailForm($event)"
>
</video-detail>

E configuramos o mtodo onCloseDetailForm da seguinte forma:

app/app.component.ts

imports....
export class AppComponent {
....
onCloseDetailForm(event){
this.selectedVideo = null;
}
....
}

Ao alterar o valor da varivel selectedVideo para null, o componente VidelDetailCompo-


nent ficar invisvel, graas ao *ngIf="selectedVideo".

3.2.15 Criando um novo item

Para finalizar a aplicao, precisamos criar um boto para adicionar um novo vdeo.
Um pouco de prtica 83

app/app.component.html
<h1 class="jumbotron">
{{title}}
</h1>

<video-list [videos]="videos"
(selectVideo)="onSelectVideo($event)">
</video-list>

<video-detail
*ngIf="selectedVideo"
[video]="selectedVideo"
(closeForm)="onCloseDetailForm($event)"
>
</video-detail>

<button type="button"
class="btn btn-default"
(click)="newVideo()">New</button>

Agora basta implementar o mtodo newVideo na classe AppComponent:

imports....
export class AppComponent{
...
newVideo(){
var v : Video = new Video(this.videos.length+1,"A new video");
this.videos.push(v);
this.selectedVideo = v;
}
...
}

3.2.16 Algumas consideraes

Esta pequena aplicao usa os conceitos mais simples do Angular 2. Por exemplo, para
preencher os dados da lista de vdeos, usamos um simples array que foi populado no
Um pouco de prtica 84

AppComponent. Em aplicaes reais os dados so requisitados ao servidor, e usado um


service para esta tarefa. Isso ser abordado em um prximo captulo.

No formulrio tambm abordamos o bsico, mas existem diversas funcionalidades embutidas


no Angular 2 que auxiliam o tratamento de erros do formulrio, no qual veremos em um
captulo posterior.

3.3 Criando Componentes

Uma das vantagens de trabalhar com componentes no Angular 2 a possibilidade de


reutilizao dos mesmos, ou seja, quando criamos um componente podemos us-lo em
qualquer lugar da aplicao. Uma das funcionalidades principais da componentizao a
criao de componenets hierrquicos, ou seja, a possibilidade de adicionarmos componentes
dentro de outros componentes, de forma livre.
Para o prximo exemplo, copie o diretrio AngularBase e cole como AngularPanel, pois
exibiremos um exemplo de como criar um componente do tipo Panel, o mesmo do Bootstrap.
Aps copiar o projeto, adicione o bootstrap pelo comando:

$ npm i bootstrap -S

Adicione a biblioteca bootstrap no arquivo index.html, conforme o cdigo a seguir:

index.html

<html>
<head>
<title>Angular Panel</title>
<base href="/">
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min\
.css">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
Um pouco de prtica 85

</head>
<body>
<div class="container">
<my-app>Loading...</my-app>
</div>
</body>
</html>

Vamos alterar o template do AppComponent para o seguinte modelo:

import {Component} from '@angular/core'

@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html'
})
export class AppComponent { }

Ento incluimos o seguinte template no app.component.html:

<br/>

<div class="panel panel-default">


<div class="panel-heading">Panel Heading</div>
<div class="panel-body">Panel Content</div>
</div>

At este momento temos um Panel do Boostrap, semelhante a imagem:


Um pouco de prtica 86

Agora vamos criar o componente Panel, no qual ir pertencer ao diretrio container,e que
ser uma library.

app/container/panel.ts

import {Component} from '@angular/core'

@Component({
selector: 'panel',
templateUrl: 'app/container/panel.html'
})
export class Panel { }

O template para o Panel , por enquanto, o mesmo cdigo html de um Panel do bootstrap:
Um pouco de prtica 87

<div class="panel panel-default">


<div class="panel-heading">Panel Heading</div>
<div class="panel-body">Panel Content</div>
</div>

Com o componente criado, podemos adicion-lo ao componente AppComponent. Deve-se


alterar o template:

app/app.component.html

<br/>
<panel></panel>

E tambm devemos adicionar o carregamento da diretiva Panel no mdulo principal:

app/app.module.ts

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


import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';


import {Panel} from './container/panel'

@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent,Panel],
bootstrap: [ AppComponent ]
})
export class AppModule { }

Veja que importamos o Panel da seguinte forma:

import {Panel} from './container'

Isso significa que temos uma library configurada no arquivo container.ts, da seguinte
forma:
Um pouco de prtica 88

app/container.ts

export * from './container/panel'

Ao atualizarmos a aplicao (lembre-se que executar o comando tsc e usar o live-server)


veremos a mesma tela, s que agora temos o componente Panel pronto. Agora podemos
criar a propriedade title no componente Panel, da seguinte forma:

app/container/panel.ts

import {Component} from '@angular/core'

@Component({
selector: 'panel',
templateUrl: 'app/container/panel.html',
inputs: ['title']
})
export class Panel { }

Perceba que inclumos na diretiva inputs do @Component o valor title, configurando assim
uma varivel de entrada no componente. Podemos us-lo no template, da seguinte forma:

app/container/panel.html

<div class="panel panel-default">


<div class="panel-heading" *ngIf="title">{{title}}</div>
<div class="panel-body">Panel Content</div>
</div>

Aqui usamos a diretiva *ngIf="title" configurando que a <div> somente ser inserida se
houver algum valor para a varivel title. Nesta div, inclumos a varivel atravs do databind
{{title}}.

Ao recompilarmos a aplicao, temos a seguinte interface:


Um pouco de prtica 89

Se, por exemplo, o *ngIf no estivesse presente na div, teramos a seguinte sada:
Um pouco de prtica 90

Agora altere o template do AppComponent, da seguinte forma:

app/app.component.html

<br/>
<panel title="Hello World"></panel>

E a interface fica semelhante a figura a seguir:


Um pouco de prtica 91

3.4 Componentes Hierrquicos

O componente Panel possui uma rea onde podemos inserir um texto, ou at mesmo outro
componente. Esta rea definida pelo elemento <ng-content></ng-content>, adicionado
no componente Panel:

app/container/panel.html

<div class="panel panel-default">


<div class="panel-heading" >{{title}}</div>
<div class="panel-body"><ng-content></ng-content></div>
</div>

No componente principal, temos a seguinte alterao:


Um pouco de prtica 92

app/app.component.html

<br/>

<panel title="Hello World">


Hello World from panel !!!!
</panel>

Aps recompilar os componentes, temos o desenho do Panel semelhante a figura a seguir:

Pode-se inclusive adicionar componentes dentro de componentes, o que permite a criao de


telas com a vantagem de reutilizao de cdigo html, veja:
Um pouco de prtica 93

app/app.component.html

<br/>

<panel title="Hello World">


<panel title="Step 1">
Open a terminal
</panel>
<panel title="Step 2">
Say hello world!
</panel>
</panel>

Este template produz o seguinte resultado:


4. Um pouco de teoria
Neste captulo estaremos revendo um pouco da teoria sobre o Angular 2. J tivemos um
primeiro contato com o framework atravs do exemplo do captulo anterior, ento agora
iremos fixar o que foi aprendido at este momento conhecendo os principais conceitos do
framework.

4.1 Viso Geral

Na documentao oficial do framework temos uma imagem que exibe tudo aquilo que voc
deve conhecer sobre o Angular 2. A imagem exibida a seguir:

Atravs desta imagem podemos destacar alguns pontos chave que o leitor deve conhecer para
que possa dominar por completo o framework. Estes pontos so:

Modulo
Componente
Template
Metadata
Servio
Diretivas
Injeo de dependncia
Um pouco de teoria 95

4.2 Mdulo (module)

Todas as aplicaes do angular podem ser compostas por diversos mdulos, que so
carregados a medida que os componentes so carregados. Um mdulo compreendido pelo
nome do arquivo sem a sua extenso.
No exemplo do captulo anterior (AngularPlaylist), temos exemplos de mdulos com o
mesmo nome da classe, ou seja, temos:

app.component.ts

export class AppComponent{

config.service.ts

export class Config{

A palavra export configura que a classe ser pblica ao mdulo. Aps criar a classe pblica
ao mdulo, podemos import-la, como fizemos em diversos pontos da aplicao:

import {Config} from './config.service'

O framework Angular 2 tambm trabalha com mdulos, como por exemplo:

import {Component} from '@angular/core'

A diferena entre importar um mdulo do Angular ou o mdulo da aplicao est na definio


do diretrio. Quando usamos @angular/core estamos referenciando o mdulo do Angular
que est no diretrio node_modules.
Um pouco de teoria 96

4.2.1 Library Module

Quando criamos vrias classes para somente um mdulo, estamos criando uma Library
(biblioteca), o que perfeitamente normal no Angular 2. Uma biblioteca pode conter
componentes, diretivas, services etc. O uso de bibliotecas no significa que deve-se criar
vrias classes em um mesmo arquivo, mas que podemos agrupar as suas chamadas a partir
de um nico ponto.
Suponha uma aplicao Angular em que as classes de modelo (que representado um objeto)
esto agrupadas no diretrio model, como no exemplo a seguir:

app/model/video.ts

export class Video{


id:number;
title:string;
url:string;
desc:string;
}

app/model/video.ts

import {Video} from './video'


export class Playlist{
videos:Array<Video>;
count():number{
return this.videos.length;
}
}

Na classe principal da aplicao, se quisermos utilizar estas classes do modelo, devemos


import-las da seguinte forma:
Um pouco de teoria 97

app/app.component.ts

import {Video} from './model/video'


import {Playlist} from './model/playlist'

At este momento o cdigo est 100% correto, mas suponha que voc deseja agrupar estas
classes em uma Library. Ento criamos o arquivo model.ts e usamos o seguinte cdigo:

app/model.ts

export * from './model/video'


export * from './model/playlist'

Com a library model criada, a importao das classes Video e Playlist se resume a:

app/app.component.ts

import {Video,Playlist} from './model'

O que deixa o cdigo muito mais limpo visualmente.

4.3 @ngModule

A partir da verso 2, um mdulo pode ser criado tambm atravs do @ngModule (antigo
@AppModule), abordado inclusive no projeto AngularBase.

4.4 Componente (component)

Um componente no Angular qualquer parte visual da sua aplicao. Na maioria das


vezes, um componente possui o decorator @Component, que contm informaes sobre o
componente como a sua diretiva, o template, o estilo css e outras. Todas as propriedades
so definidas pela sua api, disponvel neste link.
Um componente no Angular 2 possui o conceito de design reativo, isto , as alteraes de
visualizao no componente no so definidas acessando a DOM diretamente, mas sim
https://angular.io/docs/ts/latest/api/core/Component-decorator.html
Um pouco de teoria 98

alterando os estados do componente. No exemplo do captulo anterior, quando o usurio


clicava na lista de vdeos, surgia ento um novo componente na tela exibindo os detalhes
daquele vdeo. Para tornar o componente visvel na tela, em nenhum momento acessamos
a DOM do documento HTML e alteramos a propriedade display. Usamos a diretiva *ngIf
para isso:

<video-detail
*ngIf="selectedVideo"
>
</video-detail>

Componentes so a base das aplicaes em Angular 2. Sempre que estivermos criando uma
aplicao, devemos pensar em como quebr-la em componentes e fazer com que comuniquem
entre si.

4.5 Template
Uma parte importante do componente o template, que define como ele ser desenhado na
aplicao. Um template possui cdigo HTML, diretivas, chamada a eventos e tambm outros
templates. Um exemplo completo de template foi visto no captulo anterior:

<h1 class="jumbotron">
{{title}}
</h1>

<video-list [videos]="videos"
(selectVideo)="onSelectVideo($event)">
</video-list>

<video-detail
*ngIf="selectedVideo"
[video]="selectedVideo"
(closeForm)="onCloseDetailForm($event)"
>
</video-detail>

<button type="button"
(click)="newVideo()">New</button>
Um pouco de teoria 99

Perceba que existem diversas notaes no template que definem um comportamento espec-
fico. Vamos listar cada um deles a seguir:

4.5.1 Interpolation (Uso de {{ }})

O {{title}} um databind do template. Ele vai usar o valor da varivel title da classe no
template. Pode-se usar este databind em tags e atributos html, como no exemplo a seguir:

<h3>
{{title}}
<img src="{{heroImageUrl}}" style="height:{{App.Style.Height}}">
</h3>

4.5.2 Template Expressions

Alm de inserir valores, expresses podem ser usadas para se obter os mais diversos
resultados. Pode-se usar {{1+1}} para se obter o valor 2, por exemplo. Ou ento pode-se
usar {{{meuarray.length}} para obter a quantidades de itens de um array.

4.6 Property Bind

Uma propriedade no componente pode ser ligada a um evento ou mtodo do componente.


Vamos voltar a este exemplo especfico:

<video-detail
*ngIf="selectedVideo"
[video]="selectedVideo"
(closeForm)="onCloseDetailForm($event)"
>
</video-detail>

Aqui temos trs exemplos de property bind que podem ser usados para trs situaes
diferentes:

O uso o *ngIf ir determinar se o componente estar presente ou no na aplicao.


O uso do asterisco * indica ao Angular que esta propriedade pode alterar a DOM da
pgina. Isso vai alterar a forma como o Angular trata este componente, para que ele
seja otimizado.
Um pouco de teoria 100

O uso do [video]=selectedVideo indica que o valor de selectedVideo ser repassado


para a varivel video do VideoDetailComponent.
J (closeForm)="onCloseDetailForm($event)" indica um evento que ocorrer no
componente VideoDetailComponent e que executar o mtodo onCloseDetailForm.
A propriedade $event dever estar sempre presente.

Alm destes temos outro chamado de TwoWay DataBind, que indicado atravs de
[(target)], como no exemplo a seguir:

<input type="input"
[(ngModel)]="video.title">

4.6.1 Laos

Outro template expression que merece destaque so os laos, no qual usamos a diretiva
*ngFor. Perceba o uso do asterisco novamente indicando que esta diretiva altera a DOM
da aplicao. A diretiva deve ser inserida no elemento que ir se repetir. No exemplo do
captulo anterior, usamos:

<table class="table table-hover">


<thead>
<tr>
<th>ID</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr *ngFor="#v of videos" (click)="onSelect(v)">
<td>{{v.id}}</td>
<td>{{v.title}}</td>
</tr>
</tbody>
</table>

No elemento <tr> criamos o lao e usamos a expresso #v of videos, o que significa: pegue
cada elemento de videos, armazene na varivel v e renderize <tr>. Caso deseje utilizar o
ndice do array, altere a expresso para: *ngFor="let v of videos, let i=index".
Um pouco de teoria 101

4.6.2 Pipes (Operador |)

Um pipe adiciona uma transformao na expresso. O exemplo a seguir ilustra este compor-
tamento:

<div>{{ title | uppercase }}</div>

Pode-se inclusive formatar uma varivel com json, por exemplo:

<div>{{currentHero | json}}</div>

A sada seria:

{ "firstName": "Hercules",
"lastName": "Son of Zeus",
"birthdate": "1970-02-25T08:00:00.000Z",
"url": "http://www.imdb.com/title/tt0065832/",
"rate": 325, "id": 1 }

Para formatar uma data, usa-se {{ birthday | date:"MM/dd/yy" }} onde birthday um


objeto do tipo Date.

4.7 Metadata (annotation)


Os metadados so usados para fornecer informaes a uma classe, no caso do Angular so
usados decorators, conforme o exemplo a seguir:

@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
})
export class AppComponent { }

Neste exemplo, temos o uso do selector que define o seletor que ser usado no documento
html, ou seja, ao inserirmos <my-app></my-app> no documento html, o componente AppCom-
ponentser renderizado.

A propriedade templateUrl define uma url que indica o caminho do template daquele
componente. Pode-se tambm usar template diretamente como metadata, como no exemplo
a seguir:
Um pouco de teoria 102

@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

4.8 Servio (Service)

Uma classe service tem como responsabilidades prover dados, sejam eles vindo de um
servidor ou no. Na verdade a classe service uma classe TypeScript comum, mas que
possui apenas o conceito de manipulao de dados. No captulo sobre comunicao Ajax
veremos mais detalhes de como a classe funciona.

4.9 Injeo de dependncia

O conceito de injeo de dependncia no proveniente do Angular 2, mas sim da


orientao a objetos. O Angular usa este conceito para facilitar a instanciao de classes
pelos componentes, de forma a prover a instncia da classe automaticamente.
Uma classe injetada fica disponvel globalmente aplicao. Ou seja, se alteramos a
propriedade de uma classe que est injetada, esta alterao continuar ativa se a classe for
injetada em outro lugar.
Para injetar uma classe em outra, preciso inform-la no bootstrap da aplicao:

platformBrowserDynamic().bootstrapModule(AppModule.[ConfiService]);

Ou definir a classe no decorator @Component:

@Component({
providers: [ConfigService]
})
export class AppComponent { ... }

Aps a configurao, pode-se usar a seguinte sintaxe para injetar a instncia da classe:
Um pouco de teoria 103

export class AppComponent{


constructor(private _config: ConfigService){ }
}

No captulo anterior, usamos uma classe de configurao chamada de Config na qual


usamos uma propriedade esttica chamada TITLE_PAGE. Vamos alterar este comportamento,
injetando a classe Config no AppComponent.
Primeiro, retiramos o static da varivel TITLE_PAGE:

app/config.service.ts

export class Config{


/**
* Ttulo da pgina da aplicao
*/
TITLE_PAGE : string = "My Playlist";
}

Ento alteramos o bootstrap indicando que a classe Config pode ser injetada em qualquer
classe da aplicao:

boot.ts

import {bootstrap} from '@angular/platform-browser-dynamic'


import {Config} from './config.service'
import {AppComponent} from './app.component'

bootstrap(AppComponent, [Config]);

Aps adicionar a classe Config no bootstrap, alteramos a classe AppComponent, que ao invs
de referenciar o ttulo diretamente, ser referenciado no seu construtor, utilizando a classe
Config injetada.
Um pouco de teoria 104

app/app.component.ts

import {Component} from '@angular/core'


import {Config} from './config.service'
import {Video} from './video'
import {VideoListComponent} from './videolist.component'
import {VideoDetailComponent} from './videodetail.component'

@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html'
})
export class AppComponent {

title:string;
videos : Array<Video>;
selectedVideo: Video;

constructor(_config:Config){
this.title = _config.TITLE_PAGE;
....
}

...
}

4.9.1 Uso do @Injectable()

Em algumas classes onde no h nenhum metadata (@Component por exemplo) preciso


adicionar o metadata @Injectable() principalmente se esta classe usa injeo de dependn-
cia. No exemplo a seguir, a classe TestService gera um erro de execuo, pois no existe
nenhum metadata atrelado a ela, e a mesma usa injeo de dependncia com a classe Http:
Um pouco de teoria 105

import {Http} from '@angular/http'

export class TestService{


constructor(http:Http){
http.get(.......);
}
}

Para que este problema seja resolvido, basta inserir o metadata @Injectable():

import {Http} from '@angular/http'


import {Injectable} from '@angular/core'
@Injectable()
export class TestService{
constructor(http:Http){
http.get(.......);
}
}
5. Formulrios
Neste captulo tratamos as funcionalidades que o Angular 2 prov no desenvolvimento de
um formulrio web. Formulrios so usado para entrada de dados, e necessrio controlar
como esta entrada realizada e se os dados informados pelo usurio so vlidos.
Com Angular 2, possvel prover as seguintes funcionalidades:

Databind entre objetos e campos do formulrio


Capturar as alteraes no formulrio
Validar entrada de forma coerente
Capturar eventos
Exibir mensagens de erro

5.1 Criando o projeto inicial

Neste captulo, iremos copiar a aplicao AngularBase e colar como AngularForms.


Altere o arquivo app.module.ts para que ele possa carregar a biblioteca FormsModule:

app/app.module.ts

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


import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
imports: [ BrowserModule,FormsModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Formulrios 107

Antes de criarmos o primeiro formulrio, vamos criar a classe Person que ficar disponvel
na Library model. Para isso, devemos criar o arquivo app/model/person.ts e o arquivo
app/model.ts, da seguinte forma:

app/model/person.ts

export class Person {


constructor(
public id: number,
public name: string,
public email: string,
public birthdate?:string
) { }
}

Esta uma classe simples que define quatro campos, sendo que o campo birthdate
opcional. A classe model.ts exporta a classe Person, formando assim uma library:

app/model.ts

export * from './model/Person'

Agora criamos um simples service chamado Mock, que conter a informao que ser
exibida no formulrio, veja:

app/mock.ts

import {Person} from './model'


export class Mock{
public mike = new Person(1,"Mike","mike@gmail");
}

Esta classe ser injetada no componente, atravs do atributo providers que veremos a seguir.
Com o service Mock pronto para ser usado, podemos retornar a classe AppComponent e us-lo
da seguinte forma:
Formulrios 108

app/app.component.ts

import {Component} from '@angular/core'


import {Mock} from './mock'
import {Person} from './model'

@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>',
providers: [Mock]
})
export class AppComponent {
user:Person;

constructor(_mock:Mock){
this.user = _mock.mike;
}
}

Com esta configurao podemos criar um simples formulrio e adicion-lo ao componente


AppComponent, alterando a propriedade template para templateUrl, com o seguinte tem-
plate:

app/app.component.html

<form>
<input type="hidden" id="id" name="id"/>
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control" required>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
Formulrios 109

At este momento os dados do Mock ainda no foram exibidos, isso porque no configu-
ramos o Two-Way Databind. Para configur-lo, devemos usar a seguinte sintaxe: [(ngMo-
del)]="model.name". No formulrio, temos:

app/app.component.html

<form>
<input type="hidden" id="id" name="id" [(ngModel)]="user.id"/>
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control"
name="name"
required [(ngModel)]="user.name">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control"
name="email"
required [(ngModel)]="user.email">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>

Somente com esta modificao j temos os dados sendo exibidos no formulrio:


Formulrios 110

Uma simples forma de analisar a varivel user da classe AppComponent usar o seguinte
template acima do formulrio:

app/app.component.html

{{user | json}}
<form>
<input type="hidden" id="id" name="id" [(ngModel)]="user.id"/>
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control"
name="name"
required [(ngModel)]="user.name">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control"
name="email"
required [(ngModel)]="user.email">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>

Este template ir exibir a varivel user e o pipe | ir formatar em json. O resultado


semelhante a figura a seguir:
Formulrios 111

Perceba que, ao alterar o valor da caixa de texto, o valor do objeto user altera automatica-
mente.

5.2 Uso do ngControl

Permitir o data-bind do controle apenas uma das funcionalidades que o Angular prov.
Tambm possvel rastrear o estado de cada componente permitindo assim que se saiba
quando um componente foi alterado, quando est invlido etc. Alm de checar o estado atual
do controle, possvel adicionar estilos css ele, de forma que podemos destacar os estados
do controle, como um erro por exemplo.
Para habilitar esta validao, basta usar a diretiva ngControl, repassando a propriedade a ser
observada, veja:

app/app.component.html

{{user | json}}
<form>
<input type="hidden" id="id" name="id" [(ngModel)]="user.id"/>
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control"
required [(ngModel)]="user.name"
ngControl="name" name="name"
>
Formulrios 112

</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control"
required [(ngModel)]="user.email"
ngControl="email" name="email"
>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>

Ao adicionarmos o ngControl, este passa a observar o controle, e controlar os estilos CSS do


campo de acordo com o comportamento do controle. Por exemplo, o campo name possui
a instruo required, que define o campo como obrigatrio. Se este campo no estiver
preenchido, a classe css ng-invalid ser adicionada ele. Podemos esto usar um pouco
de css para exibir uma informao ao usurio. Primeiro, crie o arquivo styles.css com o
seguinte cdigo:

styles.css

.ng-invalid {
border-left: 5px solid #a94442;
}

Depois, adicione o arquivo styles.css no <head> do index.html:

<html>
<head>
<title>Angular 2 Form</title>
....
<link rel="stylesheet" href="styles.css">
....

Aps adicionar o estilo, recompile a aplicao e acesse o formulrio, retire o texto do campo
Name e acesse o campo Email. Perceba que o estilo foi aplicado, com uma borda vermelha,
conforme a imagem a seguir:
Formulrios 113

Volte a preencher o campo e veja que o estilo foi removido.

5.3 Exibindo uma mensagem de erro

Para exibir uma mensagem de erro, necessrio criar uma <div> cuja visibilidade possa ser
controlada atravs de uma varivel de controle. Para criar esta varivel, use a # seguida do
nome da varivel e do seu valor. No caso do campo name, temos:

<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control"
required [(ngModel)]="user.name"
ngControl="name"
#name="ngModel"
>
<div [hidden]="name.valid" class="alert alert-danger">
Name is required
</div>
</div>

Perceba que criamos #name="ngModel", ou seja, criamos a varivel name no campo input
apontando para ngModel, que o model em questo. Depois criamos uma div e usamos
a diretiva [hidden] para controlar a sua visibilidade. O resultado desta implementao
exibida a seguir:
Formulrios 114

5.4 Desabilitando o boto de submit do formulrio

possvel desabilitar o boto de Submit do formulrio caso existe algum problema com o
formulrio. Para isso, precisamos criar uma varivel que representa o ngForm, isso feito na
tag <form>:

<form #f="ngForm">

No boto submit podemos usar a diretiva [disabled] em conjunto com a varivel #f criada:

<button [disabled]="!f.valid"
type="submit"
class="btn btn-default">Submit</button>

Quando o formulrio estiver invlido por algum motivo, f.valid ser falso e !f.valid
verdadeiro, desabilitando o boto, conforme a imagem a seguir:
Formulrios 115

5.5 Submit do formulrio

Quando o usurio clicar no boto submit, o mesmo ser postado, o que no utilizado
pelo Angular 2, j que toda a aplicao geralmente armazenada em uma nica pgina.
Geralmente, quando um formulrio submetido, usamos Ajax para enviar estas informaes
ao servidor.
No Angular 2 podemos usar a diretiva (ngSubmit) repassando um mtodo que ser executado
no componente, como no exemplo a seguir:

app/app.component.html

<form (ngSubmit)="onSubmit(f)" #f="ngForm">

No componente, temos:

app/app.component.ts

import {Component} from '@angular/core'


import {Mock} from './mock'
import {Person} from './model'

@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
providers: [Mock]
Formulrios 116

})
export class AppComponent {
user:Person;

constructor(_mock:Mock){
this.user = _mock.mike;
}

onSubmit(f){
console.log("sending..." + JSON.stringify(user));
}
}

Ao clicar no boto submit, temos uma resposta semelhante a figura a seguir:


Formulrios 117

5.6 Controlando a visibilidade do formulrio

Uma prtica simples que ajuda o usurio a obter uma resposta ao envio do formulrio criar
uma varivel de controle que indica se o formulrio foi enviado. Com esta varivel podemos
usar [hidden] para definir o que estar visvel ao usurio. O exemplo a seguir ilustra este
processo:

app/app.component.html

<div [hidden]="submitted">
<form>
....
</form>
</div>
<div [hidden]="!submitted">
Sending... {{user|json}}
</div>

A varivel submitted controlada no componente AppComponent:

app/app.component.ts

import {Component} from '@angular/core'


import {Mock} from './mock'
import {Person} from './model'

@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
providers: [Mock]
})
export class AppComponent {
user:Person;
submitted:boolean;

constructor(_mock:Mock){
this.submitted = false;
this.user = _mock.mike;
Formulrios 118

onSubmit(f){
this.submitted = true;
console.log("sending... " + JSON.stringify(this.user));
}
}
6. Conexo com o servidor
Toda aplicao real necessita persistir dados em um banco de dados, e no desenvolvimento
web usado uma arquitetura no estilo cliente/servidor, ou seja, a aplicao Angular acessa
o servidor atravs de uma url, que por sua vez responde ao cliente.
O servidor web pode ser constitudo de qualquer linguagem (java, php, .Net), mas a
comunicao entre o servidor e o cliente deve seguir um padro de dados. Esta padro o
json, um formato de dados em texto que pode representar um objeto ou um array de objetos.

6.1 Criando o projeto

Copie o diretrio AngularBase e cole como AngularHttp. O primeiro teste que faremos
acessar uma url qualquer e obter dados via JSON. Podemos, a princpio, criar o seguinte
arquivo no projeto recm criado:

users.json

[
{"id":1,"name":"Mike"},
{"id":2,"name":"Joe"},
{"id":3,"name":"Adam"}
]

Aps criar o arquivo, execute o live-server e acesse a seguinte url: http://localhost:8080/users.json,


obtendo a seguinte resposta:
Conexo com o servidor 120

6.2 Configurando o mdulo

necessrio configurar o mdulo da aplicao (app.module.ts) para usar o Http, da seguinte


forma:

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


import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';


import { HttpModule } from '@angular/http';

@NgModule({
imports: [ BrowserModule,HttpModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Conexo com o servidor 121

6.3 Uso da classe Http

Deve-se adicionar no @Component a propriedade HTTP_PROVIDERS, importada anteriormente


que define diversas classes do Angular que podem ser injetadas no componente.

@Component({
...
providers: [HTTP_PROVIDERS],
...
})

Como abordado anteriormente, a propriedade providers pode ser substituda no bootstrap


da aplicao, no arquivo boot.ts, tornando a classe Http disponvel para qualquer classe da
aplicao.

Injete a classe Http no componente:

export class AppComponent {

constructor(private _http:Http){

}
}

Pode-se inclusive usar uma varivel de classe, como por exemplo:

export class AppComponent {


private _http;
constructor(_http:Http){
this._http = _http;
}
}

ou somente:
Conexo com o servidor 122

export class AppComponent {


constructor(private _http:Http){
this._http = _http;
}
}

Neste primeiro exemplo, iremos usar _http somente no construtor.


Com a classe devidamente injetada, vamos us-la para acessar o servidor via ajax. Como usa-
mos o live-server, ao usar o endereo ./users.json, ser acessado uma URL semelhante
a esta: http://localhost:8080/users.json.
Para acessar este endereo via o mtodo GET, usamos:

constructor(_http:Http){
_http.get("./users.json").................
}

Ou seja, usamos _http.get(url) para acesso a url e quando o servidor retorna com as
informaes, chamamos dois mtodos que tem funcionalidades distintas. O primeiro o
mtodo map que ir formatar o texto de retorno do servidor e o segundo o subscribe que
ir atribuir o texto formatado a uma varivel qualquer. Resumindo, temos:

export class AppComponent {


users:Array<any>;
constructor(_http:Http){
_http.get("./users.json")
.map(res => res.json())
.subscribe(users => this.users = users);
}
}

Neste exemplo, o mtodo map formata a resposta res em json, isso possvel porque o servidor
retorna um texto no formato json. O mtodo subscribe atribuiu a resposta j formatada em
json para a varivel this.users, criada na classe.

Pode-se, ao invs de atribuir o valor varivel, chamar um mtodo da prpria


classe, por exemplo: .subscribe(users => this.onGetUsers(users));
Conexo com o servidor 123

Com a varivel this.users devidamente preenchida, podemos usar o template para exibir
os dados. No exemplo a seguir, temos a classe AppComponent completa:

import {Component} from '@angular/core'


import {Http, HTTP_PROVIDERS} from '@angular/http'
import 'rxjs/add/operator/map'

@Component({
selector: 'my-app',
providers: [HTTP_PROVIDERS],
template: `
<ul>
<li *ngFor="let u of users">
{{u.id}} - {{u.name}}
</li>
</ul>
`
})
export class AppComponent {
users:Array<any>;
constructor(_http:Http){
_http.get("./users.json")
.map(res => res.json())
.subscribe(users => this.users = users);
}
}

A novidade na classe o template, que realiza um ngFor no elemento <li> atravs da varivel
users, que preenchida pelo Http. O resultado deste componente exibido a seguir:
Conexo com o servidor 124

6.4 Utilizando services

No exemplo anterior usamos a classe Http diretamente no componente, acessando o servidor


e obtendo o array de users, que foi atribudo varivel users. Vamos refatorar o projeto
para colocar cada funcionalidade em seu devido lugar.
Uma classe service responsvel em prover dados a aplicao, ento fica natural criarmos
a classe UserService que ter a responsabilidade de acessar o servidor e retornar com os
dados.
Conexo com o servidor 125

6.5 Organizao do projeto

Neste contexto, entra uma observao sobre a organizao de suas classes no projeto. Perceba
que temos trs alternativas a escolher, sendo elas:

1. Criar todas as classes da aplicao no diretrio app


2. Criar o diretrio services e o arquivo user.ts neste diretrio. Criar a library services
no diretrio app.
3. Criar o diretrio user e o arquivo user.service.ts neste diretrio. Criar a library
services no diretrio app.

A pior opo em termos de organizao a 1a, use-a somente quando estiver aprendendo
ou testando algo muito pequeno. Um projeto em Angular 2 divide-se em muitos arquivos e
armazen-los em somente um diretrio app no vivel.
A opo 2 boa para projetos pequenos, pois assim temos services/classes/componen-
tes/templates/estilos organizados em cada lugar, por exemplo:

app
|-components
|- user.component.ts
|- product.component.ts
|- employee.component.ts
|-
|-templates
|- user.html
|- product.html
|- employee.html
|-
|-services
|- user.ts
|- product.ts
|- employee.ts
|-
|-styles
|- app.css
|- user.css
Conexo com o servidor 126

|- product.css
|- employee.css
|-services.ts
|-app.component.ts
|-boot.ts

....

Perceba que nesta organizao os arquivos que representam as entidades da aplicao esto
misturados. Ou seja, para que voc trabalhe com products dever abrir diversos arquivos
em vrios diretrios. Isso se torna custoso quando temos muitos arquivos em um mesmo
diretrio. A segunda opo melhor que a primeira, mas funciona bem apenas em projetos
pequenos.
A 3a opo consiste em separar as entidades da aplicao em diretrios distintos, da seguinte
forma:

app
|-user
|- user.service.ts
|- user.component.ts
|- user.template.html
|- user.style.css
|-product
|- product.service.ts
|- product.component.ts
|- product.template.html
|- product.style.css
|-employee
|- employee.service.ts
|- employee.component.ts
|- employee.template.html
|- employee.style.css
|-services.ts
|-app.component.ts
|-boot.ts

Na terceira opo, separamos cada entidade em um diretrio, adicionando os arquivos


relacionados quela entidade. Desta forma, quando o projeto tornar-se demasiadamente
Conexo com o servidor 127

grande, teremos muitos diretrios, mas cada um deles representa um pedao nico da
aplicao.

6.6 Model user

Antes de criarmos a classe service, perceba que no app.component a varivel users do tipo
Array<any>, ou seja, um array de objetos de qualquer tipo. Vamos melhorar um pouco este
cdigo criando um objeto que representa o user, no qual chamaremos de model User.

app/user/user.ts

export class User{


constructor(
public id:number,
public name:string
){}
}

Nesta classe usamos public id dentro do constructor criando assim uma varivel pblica.
Em projetos maiores possvel encapsular estas variveis. Ao criar o model User, podemos
adicion-la a library model, da seguinte forma:

app/model.ts

export * from './user/user'

6.7 Service user

Podemos criar a classe UserService da seguinte forma:


Conexo com o servidor 128

app/user/user.service.ts

import {Http} from '@angular/http'


import {Injectable} from '@angular/core'
import 'rxjs/add/operator/map'
import {User} from '../model'

@Injectable()
export class UserService {
constructor(private http: Http) { }

public getUsers() {
return this.http
.get('./users.json')
.map(res => res.json());
}
}

Nesta classe, temos os imports que j vimos no incio do captulo. Uma novidade o import
do User que aplica um caminho diferente: ../model. O uso do ../ sobe um nvel de diretrio
para encontrar a classe model.ts.
Usamos @Injectable() para configurar a injeo de dependncia na classe. Com isso, ser
possvel injetar a classe Http na classe UserService. Quando criamos o construtor, injetamos
a instncia da classe Http na varivel http, que pode ser usada em outros mtodos da classe.
Para que possamos injetar a classe Http, devemos usar o metadata providers, ou alterar o
bootstrap da aplicao. Como Http uma classe que ser injetada em diversas outras classes,
vamos adicion-la no bootstrap da aplicao:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';


import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

Voltando a classe UserService, temos o mtodo getUsers():


Conexo com o servidor 129

public getUsers() {
return this.http
.get('./users.json')
.map(res => res.json());
}

Este mtodo usa a classe Http para fazer uma requisio GET ao endereo ./users.json, e na
resposta do servidor o mtodo map chamado, onde usamos o mtodo .json() para formatar
a reposta que o texto [{id:1,name:'mike'}.....] em Json.
Perceba que estamos retornando o this.http.get(...).map(...) para quem chamou o
mtodo getUsers(). O cdigo que chama getUsers() que fica responsvel em tratar este
retorno. Isso realizado no AppComponent.
Para criar uma library de services, criamos o seguinte arquivo:

app/service.ts

export * from './user/user.service'

6.8 Alterando o componente AppComponent

Agora o AppComponent ir usar a classe UserService, da seguinte forma:

app/app.component.ts

import {Component} from '@angular/core'


import {User} from './model'
import {UserService} from './service'

@Component({
selector: 'my-app',
providers: [UserService],
template: `
<ul>
<li *ngFor="let u of users">
{{u.id}} - {{u.name}}
</li>
</ul>
Conexo com o servidor 130

`
})
export class AppComponent {
public users:Array<User>;
constructor(userService:UserService){
userService.getUsers()
.subscribe(users => this.users = users);
}
}

No AppComponent importamos a classe UserService e a usamos como um provider no


@Component. Isso significa que podemos utilizar injeo de dependncia no construtor. O
construtor ir chamar o mtodo userService.getUsers() que ir retornar uma instncia da
classe Observable, na qual podemos utilizar o mtodo subscribe para preencher o valor da
varivel this.users.

6.9 Enviando dados

Para enviar dados do cliente ao servidor, faremos uma requisio POST da seguinte forma:

@Injectable()
export class UserService {
...
public addUser(u:User){
return this.http
.post('./addUser',JSON.stringify(u))
.map(res => res.json());
}
...
}

Ao invs de http.get, usamos http.post e o no segundo parmetro do .post repassamos os


dados que sero enviados ao servidor. Como ainda no estamos tratando dados no servidor,
veremos mais exemplos de alterao de dados nos prximos captulos.
7. Routes
A definio de rotas no Angular 2 segue o conceito de diviso da sua aplicao em partes
menores que podem ser carregas via Ajax, pelo prprio framework.

7.1 Aplicao AngularRoutes

Copie a aplicao AngularBase e cole como AngularRoutes.

AngularRoutes/index.html
<html>
<head>
<title>Angular Routes</title>
<base href="/">
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.m\
in.css">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<div class="container">
<my-app>Loading...</my-app>
</div>
</body>
</html>

Importante: Inclua tambm <base href="/"> dentro da seo <head> do docu-


mento html.
Routes 132

Para configurar o Router, preciso criar o arquivo um arquivo com a configurao das rotas e
referenci-los no mdulo da aplicalo. Por padro, vamos criar o arquivo app/app.routing.ts:

import { Routes, RouterModule } from '@angular/router';

// imports

const appRoutes: Routes = [


// ROUTING CONFIGURATION
];
export const appRoutingProviders: any[] = [
];
export const routing = RouterModule.forRoot(appRoutes);

Aps incluir este arquivo, basta alterar o app.module.ts para que o router seja ativado:

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


import { BrowserModule } from '@angular/platform-browser';

// imports

import { routing,
appRoutingProviders } from './app.routing';

import { AppComponent } from './app.component';

@NgModule({
imports: [ BrowserModule,routing ],
declarations: [ AppComponent,HomeComponent,DashboardComponent,LoginCompone\
nt ],
providers: [appRoutingProviders],
bootstrap: [ AppComponent ]
})
export class AppModule { }

Atravs destas duas configuraes, o Router habilitado na aplicao.


Routes 133

7.2 Dividindo a aplicao em partes


Uma aplicao pode ser dividida em diversas partes, como por exemplo: home, login e
dashboard. Cada parte possui seu componente e template, que so configurados atravs do
Router.
Primeiro, crie os seguintes componentes:

HomeComponent
LoginComponent
DashboardComponent

import {Component} from '@angular/core'


@Component({
templateUrl: 'app/home/home.html'
})
export class HomeComponent { }

import {Component} from '@angular/core'


@Component({
templateUrl: 'app/login/login.html'
})
export class LoginComponent { }

import {Component} from '@angular/core'


@Component({
templateUrl: 'app/dashboard/dashboard.html'
})
export class DashboardComponent { }

Crie os templates de cada componente somente com o nome de cada componente.

7.3 Criando a rea onde os componentes sero


carregados

preciso definir uma rea onde os componentes sero carregados. Esta definio feita com
a tag <router-outlet>, da seguinte forma:
Routes 134

app/app.component.ts

import {Component} from '@angular/core'

@Component({
selector: 'my-app',
template: `
<h1>My First Angular 2 App</h1>
<div><router-outlet></router-outlet></div>
`
})
export class AppComponent { }

7.4 Configurando o router

Para configurar o Router, alteramos o arquivo app.routing.ts:

import { Routes, RouterModule } from '@angular/router';

import {HomeComponent} from './home/home.component'


import {DashboardComponent} from './dashboard/dashboard.component'
import {LoginComponent} from './login/login.component'

const appRoutes: Routes = [


{ path: '', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'dashboard', component: DashboardComponent }
];

export const appRoutingProviders: any[] = [

];

export const routing = RouterModule.forRoot(appRoutes);

Perceba que alteramos a varivel appRoutes, com as seguintes informaes:


Routes 135

path: o caminho que dever casar com a url.


component: o componente que ser carregado

7.5 Criando links para as rotas

Vamos criar um pequeno menu que contm os links para as rotas. A princpio este menu fica
no prprio template do AppComponent, veja:

app/app.component.ts

@Component({
selector: 'my-app',
template: `
<h1>My First Angular 2 App</h1>
<ul>
<li><a [routerLink]="['/']">Home</a></li>
<li><a [routerLink]="['/login']">Login</a></li>
<li><a [routerLink]="['/dashboard']">Dashboard</a></li>
</ul>
<div><router-outlet></router-outlet></div>
`
})

Usamos [routerLink] para definir um link para a rota, onde devemos informar o nome da
rota.

7.6 Repassando parmetros

possvel repassar parmetros entre as rotas. Primeiro, deve-se adicionar o parmetro no


link do Router, como no exemplo a seguir:

{ path: 'user/:id', component: UserComponent },

Para repassar o parmetro, pode-se usar o [routerLink] da seguinte forma:


Routes 136

<a [routerLink]="['User', {id:1}]">Princess Crisis</a>

Ou ento atravs do TypeScript (com um router injetado na classe):

this.router.navigate( ['User', { id: user.id }] );

Para obter o valor do parmetro repassado:

import { Router, ActivatedRoute } from '@angular/router';

@Component({......})
export class SomeClass{
private route: ActivatedRoute,
ngOnInit() {
var id = this.route.snapshot.params['id']
}
}
8. Exemplo Final - Servidor
Aps revermos todos os conceitos relevantes do Angular 2, vamos criar um exemplo funcional
de como integrar o Angular 2 a uma api. O objetivo desta aplicao criar um simples blog
com Posts e Usurios, onde necessrio realizar um login para que que o usurio possa criar
um Post.

8.1 Criando o servidor RESTful

Usaremos uma soluo 100% Node.js, utilizando as seguintes tecnologias:

express: o servidor web que ficar responsvel em receber as requisies web vindas
do navegador e respond-las corretamente. No usaremos o live-server, mas o express
tem a funcionalidade de autoloading atravs da biblioteca nodemon.
body-parser: uma biblioteca que obtm os dados JSON de uma requisio POST.
mongoose: uma adaptador para o banco de dados MongoDB, que um banco NoSql
que possui funcionalidades quase to boas quanto a um banco de dados relacional.
jsonwebtoken: uma biblioteca node usada para autenticao via web token. Usare-
mos esta biblioteca para o login do usurio.

Todas estas tecnologias podem ser instaladas via npm, conforme ser visto a seguir.

8.2 O banco de dados MongoDB

O banco de dados MongoDB possui uma premissa bem diferente dos bancos de dados
relacionais (aqueles em que usamos SQL), sendo orientados a documentos auto contidos
(NoSql). Resumindo, os dados so armazenados no formato JSON. Voc pode instalar o
MongoDB em seu computador e us-lo, mas nesta obra estaremos utilizando o servio
https://mongolab.com/ que possui uma conta gratuita para bancos pblicos (para testes).
https://mongolab.com/
Exemplo Final - Servidor 138

Acesse o link https://mongolab.com/welcome/ e clique no boto Sign Up. Faa o cadastro no


site e logue (ser necessrio confirmar o seu email). Aps o login, na tela de administrao,
clique no boto Create New, conforme a imagem a seguir:

Na prxima tela, escolha a aba Single-node e o plano Sandbox, que gratuito, conforme a
figura a seguir:

Ainda nesta tela, fornea o nome do banco de dados. Pode ser blog e clique no boto Create
new MongoDB deployment. Na prxima tela, com o banco de dados criado, acesse-o e verifique
se a mensagem A database user is required. surge, conforme a imagem a seguir:
https://mongolab.com/welcome/
Exemplo Final - Servidor 139

Clique no link e adicione um usurio qualquer (login e senha) que ir acessar este banco,
conforme a imagem a seguir:
Exemplo Final - Servidor 140

Aps criar o usurio, iremos usar a URI de conexo conforme indicado na sua tela de
administrao:
Exemplo Final - Servidor 141

8.3 Criando o projeto

Crie o diretrio blog, e inicialize o arquivo de configurao de projetos com o seguinte


comando:

\blog $ npm init

Aps inserir as informaes sobre o projeto, o arquivo package.json criado. Vamos usar o
npm para instalar todas as bibliotecas que utilizaremos no projeto:

$ npm i --D express body-parser jsonwebtoken mongoose

E insalar o angular 2:
Exemplo Final - Servidor 142

$ npm i --S @angular/core @angular/compiler @angular/common @angular/platfor\


m-browser @angular/platform-browser-dynamic @angular/router rxjs@5.0.0-beta.\
6 zone.js@0.6.12 systemjs@0.19.27 es6-shim@0.35.0 reflect-metadata@0.1.3 ang\
ular2-in-memory-web-api@0.0.7 bootstrap

8.4 Estrutura do projeto

A estrutura do projeto est focada na seguinte arquitetura:

blog
|-.vscode (Configuraes do Visual Studio Code)
|-node_modules (Mdulos do node da aplicao)
|-app (Aplicao - arquivos TypeScript)
|-model (Arquivos de modelo do banco de dados mongoDB)
|-public (Pasta pblica com os arquivos estticos do projeto)
|-- index.html (Pgina html principal da aplicao)
|-api (Pasta virtual com a api da aplicao)
|-package.json
|-tsconfig.json (configura como os arquivos TypeScript so compilados)
|-server.js (Servidor Web Express)

A pasta app conter a aplicao Angular 2 em TypeScript, sendo que quando a aplicao
for compilada, ela ser copiada automaticamente para a pasta public. Isso significa que os
arquivos com a extenso .ts estaro localizados na pasta app e os arquivos com a extenso
.js e .js.map estaro localizados na pasta public.

8.5 Configurando os modelos do MondoDB

O Arquivo server.js contm tudo que necessrio para que a aplicao funcione como uma
aplicao web. Iremos explicar passo a passo o que cada comando significa. Antes, vamos
abordar os arquivos que representam o modelo MongoDB:
Exemplo Final - Servidor 143

/model/user.js

var mongoose = require('mongoose');


var Schema = mongoose.Schema;

var userSchema = new Schema({


name: String,
login: String,
password: String
});

module.exports = mongoose.model('User', userSchema);

O modelo User criado com o auxlio da biblioteca mongoose. Atravs do Schema criamos
um modelo (como se fosse uma tabela) chamada User, que possui os campos name, login e
password.

A criao dos Posts exibida a seguir:

/model/post.js

var mongoose = require('mongoose');


var Schema = mongoose.Schema;

var postSchema = new Schema({


title: String,
author: String,
body: String,
user: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
date: { type: Date, default: Date.now }
});

module.exports = mongoose.model('Post', postSchema);

Na criao do modelo Post, usamos quase todos os mesmos conceitos do User, exceto pelo
relacionamento entre Post e User, onde configuramos que o Post o possui uma referncia ao
modelo User.
Exemplo Final - Servidor 144

8.6 Configurando o servidor Express

Crie o arquivo server.js para que possamos inserir todo o cdigo necessrio para criar a
api. Vamos, passo a passo, explicar como este servidor configurado.

server.js

1 var express = require('express');


2 var app = express();
3 var bodyParser = require('body-parser');
4 var jwt = require('jsonwebtoken');

Inicialmente referenciamos as bibliotecas que usaremos no decorrer do cdigo. Tambm


criada a varivel app que contm a instncia do servidor express.

server.js

5 //secret key (use any big text)


6 var secretKey = "MySuperSecretKey";

Na linha 6 criamos uma varivel chamada secrectKey que ser usada em conjunto com o
mdulo jsonwebtoken, para que possamos gerar um token de acesso ao usurio, quando ele
logar. Em um servidor de produo, voc dever alterar o MySuperSecretKey por qualquer
outro texto.

server.js

7 //Database in the cloud


8 var mongoose = require('mongoose');
9 mongoose.connect('mongodb://USER:PASSWOD@___URL___/blog', function (err) {
10 if (err) { console.error("error! " + err) }
11 });

Importamos a biblioteca mongoose na linha 8 e usamos o comando connect para conectar


no banco de dados do servio mongolab. Lembre de alterar o endereo de conexo com o que
foi criado por voc.
Exemplo Final - Servidor 145

server.js

12 //bodyparser to read json post data


13 app.use(bodyParser.urlencoded({ extended: true }));
14 app.use(bodyParser.json());

Nas linhas 13 e 14 configuramos o bodyParser, atravs do mtodo use do express, que est
representado pela varivel app. O bodyParser ir obter os dados de uma requisio em JSON
e format-los para que possamos usar na aplicao.

server.js

15 //Load mongodb model schema


16 var Post = require('./model/post');
17 var User = require('./model/user');

Nas linhas 16 e 17 importamos os models que foram criados e que referenciam Post e User.
Estes esquemas (Schema) sero referenciados pelas variveis Post e User.

server.js

15 //create a REST ROUTER


16 var router = express.Router();

A linha 16 cria o router, que a preparao para o express se comportar como uma API. Um
router responsvel em obter as requisies e executar um determinado cdigo dependendo
do formato da requisio. Geralmente temos quatro tipos de requisio:

GET: Usada para obter dados. Pode ser acessada pelo navegador atravs de uma URL.
POST: Usada para inserir dados, geralmente vindos de um formulrio.
DELETE: Usado para excluir dados
PUT: Pode ser usado para editar dados. No iremos usar PUT neste projeto, mas isso
no lhe impede de us-lo.

Alm do tipo de requisio tambm temos a url e a passagem parmetros, que veremos mais
adiante.
Exemplo Final - Servidor 146

server.js

17 //Static files
18 app.use('/', express.static(__dirname+'/public'));
19 app.use('/libs', express.static(__dirname+'/node_modules/bootstrap/dist'));
20 app.use('/libs', express.static(__dirname+'/node_modules/es6-shim/'));
21 app.use('/libs', express.static(__dirname+'/node_modules/zone.js/dist/'));
22 app.use('/libs', express.static(__dirname+'/node_modules/reflect-metadata/')\
23 );
24 app.use('/libs', express.static(__dirname+'/node_modules/systemjs/dist/'));
25 app.use('/libs', express.static(__dirname+'/node_modules/rxjs/'));
26 app.use('/libs', express.static(__dirname+'/node_modules/angular2-in-memory-\
27 web-api/'));
28 app.use('/libs', express.static(__dirname+'/node_modules/@angular/'));

Na linha 18 configuramos o diretrio public como esttico, ou seja, todo o contedo neste
diretrio ser tratado como um arquivo que, quando requisitado, dever ser entregue ao
requisitante. Este conceito semelhante ao diretrio webroot de outros servidores web. Veja
que, no caso do express, os diretrios que no pertencem ao express.static no podero
ser acessados pelo navegador web. Isso melhora a segurana do servidor inibindo a exibio
de arquivos que devem ser executados somente no servidor, como o arquivo model/user.js,
por exemplo.
Tambm usamos a varivel __dirname que retorna o caminho completo at o arquivo
server.js. Isso necessrio para um futuro deploy da aplicao em servidores reais.

Nas linhas 19 22, configuramos o diretrio esttico /libs no qual ir apontar para
as bibliotecas javascript do diretrio node_modules. Estamos adicionando as bibliotecas
do Bootstrap,SystemJS, rxjs e Angular 2, todas elas que sero adicionadas no arquivo
public/index.html do projeto, no prximo captulo.
Exemplo Final - Servidor 147

server.js

23 //middleware: run in all requests


24 router.use(function (req, res, next) {
25 console.warn(req.method + " " + req.url +
26 " with " + JSON.stringify(req.body));
27 next();
28 });

Na linha 24 criamos uma funcionalidade chamada middleware, que um pedao de cdigo


que vai ser executado em toda a requisio que o express receber. Na linha 25 usamos o
mtodo console.warn para enviar uma notificao ao console, exibindo o tipo de mtodo, a
url e os parmetros Json. Esta informao usada apenas em ambiente de desenvolvimento,
pode-se coment-la em ambiente de produo. O resultado produzido na linha 24 algo
semelhante ao texto a seguir:

POST /login with {"login":"foo","password":"bar"}

O mtodo JSON.stringify, caso no conhea, obtm um objeto JSON e retorna a sua


representao no formato texto.
Na linha 27 usamos o mtodo next() para que a requisio continue o seu fluxo.

server.js

29 //middleware: auth
30 var auth = function (req, res, next) {
31 var token = req.body.token || req.query.token
32 || req.headers['x-access-token'];
33 if (token) {
34 jwt.verify(token, secretKey, function (err, decoded) {
35 if (err) {
36 return res.status(403).send({
37 success: false,
38 message: 'Access denied'
39 });
40 } else {
41 req.decoded = decoded;
Exemplo Final - Servidor 148

42 next();
43 }
44 });
45 }
46 else {
47 return res.status(403).send({
48 success: false,
49 message: 'Access denied'
50 });
51 }
52 }

Na linha 30 temos outro middleware, chamado de auth, que um pouco mais complexo e
tem como objetivo verificar se o token fornecido pela requisio vlido. Quando o usurio
logar no site, o cliente receber um token que ser usado em toda a requisio. Esta forma
de processamento diferente em relao ao gerenciamento de sesses no servidor, muito
comum em autenticao com outras linguagens como PHP e Java.
Na linha 31 criamos a varivel token que tenta recebe o contedo do token vindo do cliente.
No caso do blog, sempre que precisamos repassar o token ao servidor, iremos utilizar o
cabealho http repassando a varivel x-access-token.
Na linha 34 usa-se o mtodo jwt.verify para analisar o token, repassado pelo cliente. Veja
que a varivel secretKey usada neste contexto, e que no terceiro parmetro do mtodo
verify repassado um callback.

Na linha 35 verificamos se o callback possui algum erro. Em caso positivo, o token repassado
no vlido e na linha 36 retornarmos o erro atravs do mtodo res.status(403).send()
onde o status 403 uma informao de acesso no autorizado (Erro http, assim como 404
o not found).
Na linha 40 o token vlido, pois nenhum erro foi encontrado. O objeto decodificado
armazenado na varivel req.decoded para que possa ser utilizada posteriormente e o mtodo
next ir continuar o fluxo de execuo da requisio.

A linha 46 executada se no houver um token sendo repassado pelo cliente, retornando


tambm um erro do tipo 403.
Exemplo Final - Servidor 149

server.js

53 //simple GET / test


54 router.get('/', function (req, res) {
55 res.json({ message: 'hello world!' });
56 });

Na linha 54 temos um exemplo de como o router do express funciona. Atravs do mtodo


router.get configuramos a url /, que quando chamada ir executar o callback que
repassamos no segundo parmetro. Este callback configura a resposta do router, atravs do
mtodo res.json, retornando o objeto json { message: 'hello world!' }.

server.js

56 router.route('/users')
57 .get(auth, function (req, res) {
58 User.find(function (err, users) {
59 if (err)
60 res.send(err);
61 res.json(users);
62 });
63 })
64 .post(function (req, res) {
65 var user = new User();
66 user.name = req.body.name;
67 user.login = req.body.login;
68 user.password = req.body.password;
69
70 user.save(function (err) {
71 if (err)
72 res.send(err);
73 res.json(user);
74 })
75 });

Na linha 56 comeamos a configurar o roteamento dos usurios, que ser acessado ini-
cialmente pela url /users. Na linha 57 configuramos uma requisio GET url /users,
Exemplo Final - Servidor 150

adicionando como middleware o mtodo auth, que foi criado na linha 29. Isso significa que,
antes de executar o callback do mtodo GET /users iremos verificar se o token repassado
pelo cliente vlido. Se for vlido, o callback executado e na linha 58 usamos o schema
User para encontrar todos os usurios do banco. Na linha 61 retornamos este array de usurio
para o cliente.
Na linha 64 configuramos o mtodo POST /users que tem como finalidade cadastrar o
usurio. Perceba que neste mtodo no usamos o middleware auth, ou seja, para execut-lo
no preciso estar autenticado. Na linha 65 criamos uma varivel que usa as propriedades
do Schema User para salvar o registro. Os dados que o cliente repassou ao express so
acessados atravs da varivel req.body, que est devidamente preenchida graas ao body-
parser.
O mtodo user.save salva o registro no banco, e usado o res.json para retornar o objeto
user ao cliente.

server.js

76 router.route('/login').post(function (req, res) {


77 if (req.body.isNew) {
78 User.findOne({ login: req.body.login }, 'name')
79 .exec(function (err, user) {
80 if (err) res.send(err);
81 if (user != null) {
82 res.status(400).send('Login Existente');
83 }
84 else {
85 var newUser = new User();
86 newUser.name = req.body.name;
87 newUser.login = req.body.login;
88 newUser.password = req.body.password;
89 newUser.save(function (err) {
90 if (err) res.send(err);
91 var token = jwt.sign(newUser, secretKey, {
92 expiresIn: "1 day"
93 });
94 res.json({ user: newUser, token: token });
95 });
96 }
97 });
Exemplo Final - Servidor 151

98 } else {
99 User.findOne({ login: req.body.login,
100 password: req.body.password }, 'name')
101 .exec(function (err, user) {
102 if (err) res.send(err);
103 if (user != null) {
104 var token = jwt.sign(user, secretKey, {
105 expiresIn: "1 day"
106 });
107 res.json({ user: user, token: token });
108 }else{
109 res.status(400).send('Login/Senha incorretos');
110 }
111 });
112 }
113 });

Na linha 76 temos a funcionalidade para o Login, acessado atravs da url /login. Quando
o cliente faz a requisio POST /login verificamos na linha 77 se a propriedade isNew
verdadeira, pois atravs dela que estamos controlando se o usurio est tentando logar ou
est criando um novo cadastro.
Na linha 78 usamos o mtodo findOne repassando o filtro {login:req.body.login} para
verificar se o login que o usurio preencher no existe. O segundo parmetro deste mtodo
so os campos que devero ser retornados, caso um usurio seja encontrado. O mtodo .exec
ir executar o findOne e o callback ser chamado, onde podemos retornar um erro, j que
no possvel cadastrar o mesmo login.
Se req.body.isNew for falso, o cdigo na linha 99 executado e fazemos a pesquisa ao banco
pelo login e senha. Se houver um usurio com estas informaes, usamos o mtodo jwt.sign
na linha 103 para criar o token de autenticao do usurio, e o retornarmos na linha 106. Se
no houver um usurio no banco com o mesmo login e senha, retornamos o erro na linha
108.
Exemplo Final - Servidor 152

server.js
114 router.route('/posts/:post_id?')
115 .get(function (req, res) {
116 Post
117 .find()
118 .sort([['date', 'descending']])
119 .populate('user', 'name')
120 .exec(function (err, posts) {
121 if (err)
122 res.send(err);
123 res.json(posts);
124 });
125 })
126 .post(auth, function (req, res) {
127 var post = new Post();
128 post.title = req.body.title;
129 post.text = req.body.text;
130 post.user = req.body.user._id;
131 if (post.title==null)
132 res.status(400).send('Ttulo no pode ser nulo');
133 post.save(function (err) {
134 if (err)
135 res.send(err);
136 res.json(post);
137 });
138 })
139 .delete(auth, function (req, res) {
140 Post.remove({
141 _id: req.params.post_id
142 }, function(err, post) {
143 if (err)
144 res.send(err);
145 res.json({ message: 'Successfully deleted' });
146 });
147 });

Na linha 114 usamos /posts/:post_id? para determinar a url para obteno de posts.
Exemplo Final - Servidor 153

O uso do :post_id adiciona uma varivel a url, por exemplo /posts/5. J que usamos
/posts/:post_id?, o uso do ? torna a varivel opcional.

Na linha 115 estamos tratando o mtodo GET /posts que ir obter todos os posts do banco
de dados. Na linha 118 usamos o mtodo sort para ordenar os posts, e na linha 119 usamos o
mtodo populate para adicionar uma referncia ao modelo user, que o autor do Post. Esta
referncia possvel porque adicionamos na definio do schema de Post.
Na linha 126 criamos o mtodo POST /posts que ir adicionar um Post. Criamos uma
validao na linha 131 e usamos o mtodo Post.save() para salvar o post no banco de dados.
Na linha 139 adicionamos o mtodo DELETE /posts/, onde o post apagado do banco de
dados. Para apag-lo, usamos o mtodo Post.remove na linha 140, repassando o id (chave)
do Post e usando o parmetro req.params.post_id, que veio da url /posts/:post_id?.

server.js
148 //register router
149 app.use('/api', router);
150 //start server
151 var port = process.env.PORT || 8080;
152 app.listen(port);
153 console.log('Listen: ' + port);

Finalizando o script do servidor, apontamos a varivel router para o endereo /api, na linha
149. Com isso, toda a api ser exposta na url /api. Por exemplo, para obter todos os posts do
banco de dados, deve-se fazer uma chamada GET ao endereo /api/posts. Nas linha 151 e
152 definimos a porta em que o servidor express estar escutando e na linha 153 informamos
via console.log qual a porta foi escolhida.

8.7 Testando o servidor

Para testar o servidor Web, podemos simplesmente executar o seguinte comando:

$ node server.js

Onde temos uma simples resposta: Listen: 8080. Se houver alguma alterao no arquivo
server.js, esta alterao no ser refletida na execuo corrente do servidor, ser necessrio
terminar a execuo e reiniciar. Para evitar este retrabalho, vamos instalar a biblioteca
nodemon que ir recarregar o servidor sempre que o o arquivo server.js for editado.
Exemplo Final - Servidor 154

$ npm install nodemon -g

Aps a instalao, execute:

$ nodemon server.js

[nodemon] 1.8.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node server.js`
Listen: 8080

A resposta j indica que, sempre quando o arquivo server.js for atualizado, o comando
node server.js tambm ser.

8.8 Testando a api sem o Angular

Pode-se testar a api que acabamos de criar, enviando e recebendo dados, atravs de um
programa capaz de realizar chamadas Get/Post ao servidor. Um destes programas se chama
Postman, que pode ser instalado com um plugin para o Google Chrome.
Por exemplo, para testar o endereo http://127.0.0.1:8080/api/, configuramos o Postman
da seguinte forma:
https://www.getpostman.com/
Exemplo Final - Servidor 155

Perceba que obtemos a resposta hello world, conforme configurado no servidor. Para criar
um usurio, podemos realizar um POST url /users repassando os seguintes dados:
Exemplo Final - Servidor 156

Para testar o login, vamos tentar acessar a url /api/users. Como configuramos que esta url
deve passar pelo middleware, o token no ser encontrado e um erro ser gerado:
Exemplo Final - Servidor 157

Para realizar o login, acessamos a URL /api/login, da seguinte forma:


Exemplo Final - Servidor 158

Veja que ao repassarmos login e password, o token gerado e retornado para o postman.
Copie e cole este token para que possamos utiliz-lo nas prximas chamadas ao servidor. No
Angular, iremos armazenar este token em uma varivel.
Com o token, possvel retornar a chamada GET /users e repass-lo no cabealho da
requisio HTTP, conforme a imagem a seguir:
Exemplo Final - Servidor 159

Veja que com o token os dados sobre os usurios so retornados. Experimente alterar algum
caractere do token e refazer a chamada, para obter o erro Failed to authenticate.
9. Exemplo Final - Cliente
Com o servidor pronto, podemos dar incio a criao da estrutura do Angular 2. Ao invs
de copiar e colar o projeto AngularBase, vamos recriar cada passo da instalao do projeto
para que possamos compreender melhor o seu funcionamento.
Voltando ao servidor express, configuramos os arquivos estticos javascript da seguinte
forma:

...
app.use('/', express.static(__dirname+'/public'));
app.use('/libs', express.static(__dirname+'/node_modules/bootstrap/dist'));
app.use('/libs', express.static(__dirname+'/node_modules/es6-shim/'));
app.use('/libs', express.static(__dirname+'/node_modules/zone.js/dist/'));
app.use('/libs', express.static(__dirname+'/node_modules/reflect-metadata/')\
);
app.use('/libs', express.static(__dirname+'/node_modules/systemjs/dist/'));
app.use('/libs', express.static(__dirname+'/node_modules/rxjs/'));
app.use('/libs', express.static(__dirname+'/node_modules/angular2-in-memory-\
web-api/'));
app.use('/libs', express.static(__dirname+'/node_modules/@angular/'));
...

9.1 Arquivos iniciais

Crie o arquivo public/index.html, inicialmente com o seguinte cdigo:


Exemplo Final - Cliente 161

public/index.html

<html>
<head>
<title>Blog</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="/">
<link rel="stylesheet" href="libs/css/bootstrap.min.css">
<script src="libs/es6-shim.min.js"></script>
<script src="libs/zone.js"></script>
<script src="libs/Reflect.js"></script>
<script src="libs/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<div class="container">
<my-app>Loading...</my-app>
</div>
</body>
</html>

O documento html que contm a configurao inicial da aplicao blog possui algumas dife-
renas em relao aos outros que criamos durante esta obra. Primeiro, estamos adicionando
todas as bibliotecas utilizando o caminho /libs, que fisicamente no existe, mas foi criado
virtualmente no express. Isso importante para no expor toda a pasta node_modules ao
acesso pblico.
O arquivo systemjs.config.js exibido a seguir:
Exemplo Final - Cliente 162

(function(global) {
var map = {
'app': 'app', // 'dist',
'@angular': 'node_modules/@angular',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
'rxjs': 'node_modules/rxjs'
};
var packages = {
'app': { main: 'boot.js', defaultExtension: 'js'\
},
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js'\
},
};
var ngPackageNames = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router',
'router-deprecated',
'upgrade',
];
function packIndex(pkgName) {
packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'j\
s' };
}
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js\
', defaultExtension: 'js' };
}
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
ngPackageNames.forEach(setPackageConfig);
var config = {
Exemplo Final - Cliente 163

map: map,
packages: packages
};
System.config(config);
})(this);

Aps adicionar as bibliotecas, iniciamos a configurao do systemjs.config.js, que


idntica aos exemplos anteriores, mas possui um detalhe muito importante. Como o arquivo
index.html est na pasta public, ao configurarmos 'app': 'app' estamos na verdade
executando o arquivo public/app/boot.js, que a princpio ainda no existe. Perceba que
no podemos configurar o import com o caminho ../app/boot para acessar o diretrio
blog/app, pois este no visvel para acesso. Isso significa que neste projeto teremos os
arquivos TypeScript no diretrio /blog/app e os arquivos js e js.map (so os arquivos
compilados do TypeScript) no diretrio blog/public/app. Para que esta configurao seja
possvel, precisamos configurar o arquivo tsconfig.json da seguinte forma:

blog/tsconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "system",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false,
"watch":true,
"outDir": "./public/app"
},
"exclude": [
"node_modules"
]
}

Veja que o arquivo tsconfig.json muito semelhante aos anteriores, tendo como diferena
o atributo outDir, onde indicamos um diretrio em que os arquivos compilados sero criados.
Neste contexto usamos o caminho ./public/app.
Exemplo Final - Cliente 164

Os arquivos app/boot.ts e app/component.ts podem ser criados, a princpio, com o mesmo


cdigo da aplicao AngularBase:

app/boot.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';


import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

Veja que o bootstrap j carrega HTTP_PROVIDERS, pois iremos injetar Http no services.
A classe AppComponent, inicialmente, pode ser a seguinte:

import {Component} from '@angular/core'

@Component({
selector: 'my-app',
template: '<h1>My Blog</h1>'
})
export class AppComponent { }

Antes de compilar a aplicao, se estiver utilizando o Visual Studio Code, configure o arquivo
.vscode/tasks.json (ele ser criado na primeira vez que pressionar ctrl+shift+b) com o
seguinte texto:

.vscode/tasks.json

{
"version": "0.1.0",
"command": "tsc",
"isShellCommand": true,
"showOutput": "silent",
"problemMatcher": "$tsc"
}

Ao compilarmos a aplicao, pressionando ctrl+shift+b no Visual Studio Code, ou digitando


tsc no terminal (no diretrio blog), a compilao feita e os arquivos js e map so gerados
em public/app. A estrutura de diretrios igual a exibida a seguir:
Exemplo Final - Cliente 165

Para testar no navegador, use o terminal e no diretrio blog digite:

$ nodemon server.js

[nodemon] 1.8.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node server.js`
Listen: 8080

Acesse http://localhost:8080/ e obtenha o resultado semelhante a figura a seguir:


Exemplo Final - Cliente 166

9.2 Preparando o Template base da aplicao

O arquivo index.html possui a chamada ao elemento <my-app> e nele que configuramos


a base da aplicao, que est instanciada na classe AppComponent. Geralmente todo o HTML
da aplicao (incluindo menu e rea de contedo) adicionada ao AppComponent, e para ele
criaremos um arquivo de template chamado appComponent.html que ficar localizado no
diretrio public. Isso necessrio porque somente o diretrio public visvel a aplicao.
Crie o arquivo public/appComponent.html, com o seguinte texto:
Exemplo Final - Cliente 167

public/appComponent.html

<h1>My Blog</h1>

E alterarmos o AppComponent para:

import {Component} from '@angular/core'

@Component({
selector: 'my-app',
templateUrl: 'appComponent.html'
})
export class AppComponent { }

Teremos o mesmo resultado, mas com o template separado do componente. Neste template,
podemos usar algumas classes css do bootstrap para estilizar a aplicao. A princpio,
podemos adicionar o seguinte html:

public/appComponent.html

<nav class="navbar navbar-inverse navbar-fixed-top">


<div class="container">
<div class="navbar-header">
<button type="button"
class="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#navbar"
aria-expanded="false"
aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#"> BLOG </a>
</div>
<div id="navbar" class="collapse navbar-collapse">
Exemplo Final - Cliente 168

<ul class="nav navbar-nav">


<!-- -->
<!-- MENU -->
<!-- -->
</ul>
</div>
</div>
</nav>
<div style="padding-top:50px">
CONTEUDO
</div>

Veja que separamos a aplicao em um menu e o seu contedo. Iremos a partir deste ponto
implementar o router.

9.3 Implementando o roteamento (Router)

Para implementar o router na aplicao, precisamos realizar as seguintes configuraes:

Dividir a aplicao em componentes


Configurar o AppComponent
Incluir o menu
Configurar o html incluindo <router-outlet>

9.3.1 Criando componentes

Cada tela de uma aplicao deve ser um componente. Neste pequeno blog, teremos trs telas:

1. HomeComponent: Exibe todos os posts


2. LoginComponent: Formulrio de login
3. AddPostComponent: Adiciona um post

Os componentes podem ser criados no diretrio app/components, a princpio sem nenhuma


informao:
Exemplo Final - Cliente 169

app/component/home.ts

import {Component} from '@angular/core'

@Component({
template: `HomeComponent`
})
export class HomeComponent {

app/component/login.ts

import {Component} from '@angular/core'

@Component({
template: `LoginComponent`
})
export class LoginComponent {

app/component/addpost.ts

import {Component} from '@angular/core'

@Component({
template: `AddPostComponent`
})
export class AddPostComponent {

Para definir uma library destes componentes, crie o arquivo app/component.ts com o
seguinte cdigo:
Exemplo Final - Cliente 170

export * from './component/home'


export * from './component/login'
export * from './component/addpost'

Atravs desta library, podemos referenciar as classes de componente da seguinte forma:

import {HomeComponent,LoginComponent,AddPostComponent} from './component'

O que melhor do que importar desta forma:

import {HomeComponent} from './component/home'


import {HomeComponent} from './component/home'
import {AddPostComponent} from './component/addpost'

9.3.2 Configurando o @RouteConfig

Com os componentes prontos, podemos voltar ao AppComponent e configurar o router atravs


da diretiva RouterConfig:

app/app.component.ts
import {Component} from '@angular/core'
import {ROUTER_DIRECTIVES, ROUTER_PROVIDERS, Routes} from '@angular/router'
import {HomeComponent,LoginComponent,AddPostComponent} from './component'

@Component({
selector: 'my-app',
providers: [ROUTER_PROVIDERS],
templateUrl:'appComponent.html',

})
@Routes([
{ path: '/', component: HomeComponent},
{ path: '/Login', component: LoginComponent },
{ path: '/Addpost', component: AddPostComponent }
])
export class AppComponent {

}
Exemplo Final - Cliente 171

Veja que importamos ROUTER_PROVIDERS que devem ser adicionados as propriedades provi-
ders do @Component. Depois usamos o @Routes para criar trs rotas, ligando cada uma delas
aos componentes criados.

9.3.3 Configurando o menu

O menu da aplicao deve estar integrado as rotas. Para isso, edite o arquivo public\appComponent.html
incluindo o seguinte menu:

public\appComponent.html

<nav class="navbar navbar-inverse navbar-fixed-top">


<div class="container">
<div class="navbar-header">
<button type="button"
class="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#navbar"
aria-expanded="false"
aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">{{title}}</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">

<li><a [routerLink]="['/']">Home</a></li>
<li><a [routerLink]="['/Login']">Login</a></li>
<li><a [routerLink]="['/Addpost']">Add Post</a></li>

</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div style="padding-top:50px">
Exemplo Final - Cliente 172

CONTEUDO
</div>

9.3.4 Configurando o router-outlet

Para finalizar a criao do Router, preciso informar onde os componentes sero carregados.
Isso realizado atravs da tag <router-outlet> que deve ser inserida no template que contm
a configurao do router:

public\appComponent.html

<nav class="navbar navbar-inverse navbar-fixed-top">


<!-- ... MENU .... -->
</nav>
<div style="padding-top:50px">
<router-outlet></router-outlet>
</div>

Para testar a aplicao, recarregue a pgina e clique nos menus para verificar o contedo
sendo carregado.

9.4 Exibindo Posts

No componente HomeComponent, vamos exibir os posts que esto cadastrados no banco. Para
isso, faremos uma chamada GET ao endereo /api/posts, que no necessita de autenticao.
Ao invs de programar esta chamada no componente, vamos criar um service, que ser
chamado de PostService e o model Post que contm a definio de um post, veja:
Exemplo Final - Cliente 173

import {User} from '../model'


export class Post{
public _id:string;
public title: string;
public user: User;
public body: string;
public date: Date
constructor(){}
}

E a classe user.ts:

export class User{


public _id:string;
public name: string;
public email: string;
public password: string;
public isNew: Boolean;
constructor(){}
}

E vamos criar a library tambm:

app/model.ts

export * from './model/post'


export * from './model/user'

O service usa a classe Http para fazer a chamada ao servidor:


Exemplo Final - Cliente 174

app/service/post.ts

import {Http, HTTP_PROVIDERS} from '@angular/http'


import {Injectable} from '@angular/core'
import 'rxjs/add/operator/map' // <<<<<<<

@Injectable()
export class PostService {
constructor(private http: Http) { }
public getPosts() {
return this.http
.get('./api/posts')
.map(res => res.json());
}
}

Usamos o recurso de injeo de dependncia da classe Http, que foi configurado no bootstrap
da aplicao (app/boot.ts). O mtodo getPosts ir fazer uma requisio ajax ao endereo
./api/posts e retornar uma instncia da classe Observable do Angular 2, que ser tratada
na classe de quem realizou a chamada ao mtodo getPosts().
Como queremos exibir os posts na pgina principal, devemos configurar o HomeController
para acessar o este service. Isso feito da seguinte forma:

app/component/home.ts

import {Component} from '@angular/core'


import {PostService} from '../service/post'
import {Post} from '../model'

@Component({
providers: [PostService],
template: "HomeComponent"
})
export class HomeComponent {
public posts: Array<Post>;
constructor(private postService: PostService) {
postService.getPosts().subscribe(
p => this.posts = p,
Exemplo Final - Cliente 175

err => console.log(err)


);
}
}

Importamos PostService e o adicionamos aos providers do componente. Com isso pode-


remos injet-lo no mtodo construtor. Aps injet-lo, chamamos postService.getPosts()
que, quando responder com os posts, executa o mtodo subscribe onde possvel obter
os posts ou tratar algum eventual erro. Repare que os posts sero armazenados na varivel
this.posts, na qual podemos us-la para exibir os posts na pgina.

Para finalizar, alteramos o template do componente para:

// imports...
@Component({
providers: [PostService],
template: `
<div class="jumbotron" *ngFor="let p of posts">
<h1>{{p.title}}</h1>
<p>content</p>
</div>
`
})
export class HomeComponent { ..... }

Usamos *ngFor para realizar um loop entre os itens de posts e, por enquanto, exibimos o
ttulo do post. O resultado semelhante a imagem a seguir:
Exemplo Final - Cliente 176

9.5 Login

A tela de login definida pelo LoginComponent, que possui a seguinte estrutura:

app/component/login.ts

import {Component} from '@angular/core'


import {User} from '../model'
import {UserService} from '../service/user'
import {LoginService} from '../service/login'
import {Router} from '@angular/router'

@Component({
providers: [UserService],
template: `
>>TEMPLATE<<
`
})
export class LoginComponent {
private user:User=new User();
private showLoading:boolean = false;
private errorMessage:string = null;
Exemplo Final - Cliente 177

constructor(private userService:UserService,
private loginService:LoginService,
private router:Router){

}
onClick(event){
event.preventDefault();
this.showLoading = true;
this.errorMessage = null;
this.userService.insert(this.user).subscribe(
result => this.onLoginResult(result),
error => this.onLoginError(error)
);
}
onLoginResult(result){
console.log(result);
this.loginService.setLogin(result.user,result.token);
this.router.navigate( ['/'] );
}
onLoginError(error){
this.showLoading = false;
this.errorMessage = error._body;
}
}

Antes de exibir o template (que um pouco mais complexo que o template do HomeCon-
troller), vamos analisar como o LoginComponent funciona. Nos imports, percebe-se que
estamos utilizando UserService e LoginService, classes que tem como objetivo prover dados
a classe do componente. Veremos estas classes em breve!
No LoginComponent, temos duas variveis que controlam o template da aplicao. Por
exemplo, showLoading ir controlar se uma mensagem Carregando ser exibida, como no
exemplo a seguir:

<div class="col-md-4 col-md-offset-4" *ngIf="showLoading">


Aguarde...
</div>
Exemplo Final - Cliente 178

Com o template acima, possvel configurar a sua visualizao apenas definindo o valor da
varivel showLoading para true ou false.
O template completo do LoginComponent exibido a seguir:

<div class="col-md-4 col-md-offset-4" *ngIf="!showLoading">

<div *ngIf="errorMessage" class="alert alert-danger" role="alert">


{{errorMessage}}
</div>

<form ngForm>
<div class="form-group">
<label for="login">Login</label>
<input type="text" class="form-control"
id="login"
required
placeholder="Login"
[(ngModel)]="user.login">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control"
id="password"
required
placeholder="Password"
[(ngModel)]="user.password">
</div>
<div class="checkbox">
<label>
<input id="createAccount" type="checkbox"
[(ngModel)]="user.isNew"> Create Account?
</label>
</div>
<div class="form-group" *ngIf="user.isNew">
<label for="login">Your Name</label>
<input type="text" class="form-control"
id="name"
Exemplo Final - Cliente 179

placeholder="Your Name"
[(ngModel)]="user.name">
</div>

<button type="submit" class="btn btn-default pull-right"


(click)="onClick($event)" >Login</button>

</form>
</div>

<div class="col-md-4 col-md-offset-4"


*ngIf="showLoading">
Aguarde...
</div>

9.6 Services

Algumas classes como LoginService e HeadersService podem ser usadas em vrios com-
ponentes, ento eles so injetados no arquivo boot.ts, veja:

app/boot.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';


import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

Existem alguns services que so usados em poucas classes, como no exemplo do UserService,
ento ele injetado na classe atravs do providers, como foi visto no LoginComponent.

9.6.1 LoginService

A classe LoginService prov algumas informaes sobre o login do usurio:


Exemplo Final - Cliente 180

app/service/login.ts

import {Injectable} from '@angular/core'


import {User} from '../model'

@Injectable()
export class LoginService {
private user:User=null;
private token:string=null;
constructor() { }
setLogin(u:User,t:string){
this.user = u;
this.token = t;
}
getToken():string{
return this.token;
}
getUser(){
return this.user;
}
isLogged(){
return this.user!=null && this.token!=null;
}
logout(){
this.user = null;
this.token = null;
}
}

9.6.2 UserService

A classe UserService tem a responsabilidade de inserir um usurio.


Exemplo Final - Cliente 181

import {Http, Headers} from '@angular/http'


import {Injectable} from '@angular/core'
import 'rxjs/add/operator/map'
import {User} from '../model'
import {HeadersService} from './headers'

@Injectable()
export class UserService {
constructor(private _http: Http, private _header:HeadersService) {

}
public insert(u:User) {
return this._http
.post('./api/login',
JSON.stringify(u),
this._header.getJsonHeaders())
.map(res => res.json());
}
}

9.6.3 HeadersService

Esta classe usada para fornecer informaes de cabealho http s requisies que o cliente
faz ao servidor:

import {Injectable} from '@angular/core'


import {Headers} from '@angular/http'

@Injectable()
export class HeadersService {
constructor(){}

getJsonHeaders(token?:string){
var headers = new Headers();
headers.append('Content-Type', 'application/json');
if (token)
headers.append('x-access-token',token)
Exemplo Final - Cliente 182

return {headers: headers};


}

O mtodo getJsonHeaders retorna um cabealho configurado para o formato JSON, e caso


a propriedade token seja repassada, ela adicionada ao cabealho. Toda requisio Http
realizada do cliente ao servidor possui um cabealho no qual podemos repassar algumas
informaes. Neste caso, estamos repassando o Content-Type e o x-access-token.

9.7 Conectando no servidor

Vamos analisar como o Angular conecta no servidor e obtm informaes. Na LoginCompo-


nent, temos o boto de Login com a seguinte ao: (click)="onClick($event)". Quando o
usurio clica no boto, o mtodo onClick da classe LoginComponent disparado, que possui
o seguinte cdigo:

app/component/login.ts

import {Component} from '@angular/core'


import {User} from '../model'
import {UserService} from '../service/user'
import {LoginService} from '../service/login'
import {Router} from '@angular/router';

@Component({
providers: [UserService],
template: `

<div class="col-md-4 col-md-offset-4" *ngIf="!showLoading">

<div *ngIf="errorMessage" class="alert alert-danger" role="alert">


{{errorMessage}}
</div>

<form ngForm>
<div class="form-group">
<label for="login">Login</label>
<input type="text" class="form-control" id="login" required plac\
Exemplo Final - Cliente 183

eholder="Login" [(ngModel)]="user.login">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" id="password" requir\
ed placeholder="Password" [(ngModel)]="user.password">
</div>
<div class="checkbox">
<label>
<input id="createAccount" type="checkbox" [(ngModel)]="user.isNe\
w"> Create Account?
</label>
</div>
<div class="form-group" *ngIf="user.isNew">
<label for="login">Your Name</label>
<input type="text" class="form-control" id="name" placeholder="Y\
our Name" [(ngModel)]="user.name">
</div>

<button type="submit" class="btn btn-default pull-right" (click)="on\


Click($event)" >Login</button>

</form>
</div>

<div class="col-md-4 col-md-offset-4" *ngIf="showLoading">


Aguarde...
</div>
`
})
export class LoginComponent {
private user:User=new User();
private showLoading:boolean = false;
private errorMessage:string = null;
constructor(private userService:UserService,
private loginService:LoginService,
private router:Router){
Exemplo Final - Cliente 184

}
onClick(event){
event.preventDefault();
this.showLoading = true;
this.errorMessage = null;
this.userService.insert(this.user).subscribe(
result => this.onLoginResult(result),
error => this.onLoginError(error)
);
}
onLoginResult(result){
console.log(result);
this.loginService.setLogin(result.user,result.token);
this.router.navigate( ['Home'] );
}
onLoginError(error){
this.showLoading = false;
this.errorMessage = error._body;
}
}

Inicialmente o mtodo onClick chama event.preventDefault(), fazendo com que o envio


do formulrio seja cancelado (j que vamos usar ajax). Ento exibimos uma mensagem
de Carregando para mostrar ao usurio que algo est sendo processado. importante
tambm esconder o formulrio, para que o usurio no clique duas vezes no boto. O mtodo
insert da classe userService chamado, mtodo este que vai conectar no servidor enviando
this.user no formato json. Quando o service retornar com os dados do servidor, o mtodo
subscribe() executado e ele possui dois callbacks: result e error. Para cada um deles
criamos um mtodo no prprio componente para que possamos trat-lo.
O mtodo onLoginResult executado quando o usurio est devidamente autenticado.
Usamos a classe LoginService para informar este login, e ele poder ser usado em qualquer
lugar da aplicao (essa uma das vantagens da injeo de dependncia). Depois usamos o
router para navegar de volta ao Home.

Caso ocorra algum erro o mtodo onLoginError ser disparado. Ento escondemos a
mensagem de Carregando e exibimos a mensagem de erro. Veja que, apenas por preencher
a varivel this.errormessage, o div ser visvel na tela.
Exemplo Final - Cliente 185

9.8 Posts

Aps o usurio logar, ele poder clicar no link AddPost, que ser redirecionado para o
component AddPostComponent.

app/component/addPost.ts

import {Component} from '@angular/core'


import {Post} from '../model'
import {LoginService} from '../service/login'
import {Router} from '@angular/router'
import {PostService} from '../service/post'

@Component({
providers: [PostService],
template: `
>>TEMPLATE<<
`
})
export class AddPostComponent {

private post:Post = new Post();


private errorMessage:string = null;
private showLoading:boolean = false;

constructor(private _loginService:LoginService,
private _router:Router,
private _postService:PostService) {
if (!_loginService.isLogged())
this._router.navigate( ['Login'] );
this.post.user = this._loginService.getUser();
}
onClick(event){
event.preventDefault();
this.showLoading = true;
this.errorMessage = null;
this._postService.insert(this.post).subscribe(
result => this.onInsertPostResult(result),
Exemplo Final - Cliente 186

error => this.onInsertPostError(error)


);
}
onInsertPostResult(result){
this._router.navigate( ['Home'] );
}
onInsertPostError(error){
this.showLoading = false;
this.errorMessage = error._body;

}
}

O componente AddPostComponent tem vrias semelhanas com o formulrio de Login. A


forma como exibimos erros e a mensagem e Carregando a mesma. Uma novidade
que usamos o service LoginService para verificar se o usurio est logado, e e caso negativo
redirecionamos para o formulrio de login.
Uma diferena pequena em relao ao componente LoginComponent que usamos o nome
das variveis injetadas (LoginService, PostService) com o prefixo _, ou seja, usamos _post-
Service e _loginService. Voc pode escolher o que mais combina com o seu projeto.

O template desta tela apresentado a seguir:

<div class="col-md-4 col-md-offset-4" *ngIf="showLoading">


Aguarde...
</div>
<div class="col-md-8 col-md-offset-2" *ngIf="!showLoading">
<div *ngIf="errorMessage" class="alert alert-danger" role="alert">
{{errorMessage}}
</div>
<div class="panel panel-default">
<div class="panel-heading">Add Post</div>
<div class="panel-body">
<form ngForm>
<div class="form-group">
<label for="title">Title</label>
<input type="text" class="form-control"
Exemplo Final - Cliente 187

id="title" required placeholder="Title"


[(ngModel)]="post.title">
</div>
<div class="form-group">
<label for="text">Text</label>
<textarea rows=10 cols=100 class="form-control"
id="text" [(ngModel)]="post.text"></textarea>
</div>
<button type="submit" class="btn btn-default pull-right"
(click)="onClick($event)">Create</button>
</form>
</div>
</div>
</div>

9.8.1 PostService

A classe PostService responsvel em conectar no servidor e realizar trs operaes bsicas:


obter posts, incluir posts e excluir posts:

app/service/post.ts

import {Http} from '@angular/http'


import {Injectable} from '@angular/core'
import 'rxjs/add/operator/map'
import {Post} from '../model'
import {HeadersService} from '../service/headers'
import {LoginService} from '../service/login'

@Injectable()
export class PostService {
constructor(private _http: Http,
private _headerService:HeadersService,
private _loginService:LoginService) { }
public getPosts() {
return this._http
.get('./api/posts')
.map(res => res.json());
}
Exemplo Final - Cliente 188

public insert(p:Post){
return this._http
.post('./api/posts', JSON.stringify(p),
this._headerService.
getJsonHeaders(this._loginService.getToken()))
.map(res => res.json());
}
public delete(p:Post){
return this._http
.delete('./api/posts/' + p._id ,
this._headerService.
getJsonHeaders(this._loginService.getToken()))
.map(res => res.json());
}
}

O mtodo getPosts realiza uma chamada GET /api/posts ao servidor. O mtodo insert
ir realizar uma chamada POST /api/posts, mas aqui temos um detalhe importante:

.post('./api/posts',
JSON.stringify(p),
this._headerService.
getJsonHeaders(this._loginService.getToken())
)

Perceba que usamos a classe HeaderService para chamar o mtodo getJsonHeaders, que
ir formatar o cabealho da requisio (Requisio HTTP) como JSON (application/json).
Pode-se conferir este comportamento analisando a requisio na aba networking do Google
Chrome Developer Tools. Alm desta formatao, repassamos como parmetro o Token, pois
neste estgio o usurio tem que estar logado.
O mtodo delete adiciona na url o id do post, juntamente com o Token atravs do
HeaderService.

9.9 Refatorando a tela inicial

Para finalizar este pequeno sistema, vamos retornar ao template do HomeComponent, que antes
exibia o ttulo dos posts e adicionar mais algumas funcionalidades, veja:
Exemplo Final - Cliente 189

app/component/home.ts

import {Component} from '@angular/core'


import {PostService} from '../service/post'
import {Post} from '../model'
import {LoginService} from '../service/login'
import {User} from '../model';

@Component({
providers: [PostService],
template: `
<div class="alert alert-info" *ngIf="showLoading">
Aguarde...
</div>
<div *ngIf="!showLoading">
<div *ngIf="_loginService.isLogged()"
class="alert alert-success">
Ol {{_loginService.getUser().name}}
<a href="#" (click)="logout($event)"
class="pull-right" >
Sair</a>
</div>
<div class="jumbotron" *ngFor="let p of posts">
<h1>{{p.title}}</h1>
<p>{{p.text}}</p>
<p>Por: {{p.user?.name}}</p>
<a href="#" (click)="deletePost(p)"
*ngIf="checkPost(p)">Apagar</a>
</div>
</div>
`
})
export class HomeComponent {

private posts: Array<Post>;


private showLoading:boolean=false;
Exemplo Final - Cliente 190

constructor(private _postService: PostService,


private _loginService:LoginService) {
this.loadAllPosts();
}
loadAllPosts(){
this.showLoading = true;
this._postService.getPosts().subscribe(
p => this.onLoadAllPostsResult(p),
err => console.log(err)
);
}
onLoadAllPostsResult(p){
this.posts = p;
this.showLoading = false;
}
logout(event){
this._loginService.logout();
}
checkPost(p:Post):boolean{
try {
if (p.user == null) return false;
if (!this._loginService.isLogged()) return false;
return p.user._id==this._loginService.getUser()._id;
} catch (error) {
return false;
}
return false;
}
deletePost(p){
this._postService.delete(p).subscribe(
result => this.onDeletePostResult(result),
error => this.onDeletePostError(error)
)
}
onDeletePostResult(result){
this.loadAllPosts();
}
onDeletePostError(error){
Exemplo Final - Cliente 191

console.log(error);
}
}

Existem duas diferenas importantes no componente. A primeira que inclumos uma barra
exibido se o usurio est logado:

<div *ngIf="_loginService.isLogged()"
class="alert alert-success">
Ol {{_loginService.getUser().name}}
<a href="#" (click)="logout($event)"
class="pull-right" >
Sair
</a>
</div>

Veja que usamos LoginService para controlar tanto a visibilidade quanto as informaes
do login. Tambm criamos um mtodo logout que ir chamar o mtodo this._loginSer-
vice.logout(), atualizando toda a tela novamente.

Outro detalhe que inclumos o boto Excluir em cada Post:

<a href="#" (click)="deletePost(p)"


*ngIf="checkPost(p)">Apagar</a>

A visibilidade do link controlada pelo mtodo checkPost que retorna verdadeiro se, e
somente se, o usurio logado o dono do Post.
Aps estas modificaes, a tela principal do sistema fica semelhante figura a seguir:
Exemplo Final - Cliente 192

9.10 Concluso

Ainda existem alguns detalhes a serem realizados no projeto blog, no qual deixaremos como
exerccio para o leitor. Por exemplo, a edio de Posts, a troca de senha, envio de senha por
email, incluso de comentrios etc. Todos estes processos usam os mesmos conceitos que
aprendermos no decorrer da obra.
10. Utilizando Sublime Text
Em toda nossa obra usamos o Visual Studio Code como IDE para a criao de nossos
projetos. Durante o lanamento do livro, alguns leitores nos pediram para comentar um
pouco tambm sobre a integrao do Angular 2 com o Sublime Text, pois esse era o editor de
cdigo que mais usam.

10.1 Instalao

Se deseja instalar o Sublime Text, recomendamos a verso 3, que pode ser encontrada em
(neste link)[http://www.sublimetext.com/3]. Faa o download de acordo com a verso do seu
sistema operacional, e aps instalar o editor, voc dever instalar um plugin chamado Pac-
kage Control. Este plugin encontrado (neste link)[https://packagecontrol.io/installation#st3].
O processo de instalao dele realizado da seguinte forma:

Copie o texto de instalao, certifique-se que a aba Sublime Text 3 est ativa.
Com o editor aberto, v at View > Show Console
Com o console aberto, cole o texto que copiou no site e pressione enter

Aguarde alguns at a instalao terminar. Se surgir alguma mensagem de erro, reinicie o


editor para que as bibliotecas sejam recarregadas.

Lembre-se que precisamos ter node e typescript instalados, conforme visto nos
captulos anteriores.

10.2 Adicionando suporte a linguagem TypeScript

Com o Package Control instalado, vamos instalar outro plugin que dar suporte a linguagem
TypeScript . Pressione Ctrl+Shift+p e digite install at surgir a ao Package Control:
Install Package, semelhante a figura a seguir:
Utilizando Sublime Text 194

Surge a lista de plugins que podem ser instalados no Sublime Text. Escreva Typescript e
instale o plugin. Aps a instalao, j podemos testar o TypeScript. Acesse File>open Folder
e abra um diretrio vazio. Adicione o arquivo (File > New File) index.ts e inclua algum
cdigo TypeScript, como no exemplo a seguir:
Utilizando Sublime Text 195

class HelloWorld{
constructor(){

}
static say(){
return "Hello World";
}
}

Aps a criao da classe, pressione ctrl+b para iniciar o processo de compilao. Na caixa de
texto Build Parameters que abre, deixe em branco e pressione enter. O Plugin ir executar
o comando tsc internamente, assim como feito no Visual Studio Code e o arquivo com a
extenso .js ser criado.

10.3 Automatizando a build TypeScript

Para que o processo de build seja automatizado, podemos criar o arquivo tsconfig.json com
o seguinte cdigo:

{
"compilerOptions": {
"target": "es6",
"module": "system",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false,
"watch": true,
"outDir": "./public/app"
},
"exclude": [
"node_modules"
]
}
Utilizando Sublime Text 196

Aps criar o arquivo, compile a aplicao com ctrl+b e veja que o diretrio public foi criado,
conforme a propriedade outDir da configurao.
11. Publicando a aplicao em um
servidor cloud
Como etapa final desta obra, precisamos viabilizar a publicao da aplicao em um servidor
real, no qual poderemos disponibilizar a aplicao para todos. At esse momento, criamos a
aplicao localmente e usamos o comando node server.js para iniciar o servidor express.
Usamos Node e Mongo para servir a aplicao em Angular 2, e iremos partir deste mesmo
princpio para public-la.

Este captulo requer um pouco de conhecimento em ambientes Linux. Expresses


como root, sudo, ssh, nano, devem ser compreendidas para que o leitor possa criar
a sua aplicao em um servidor real.

Para que possamos publicar a aplicao, necessrio escolher um servio de hospedagem


cloud, que possa oferecer acesso direto ao servidor. Isso diferente dos planos de hospedagem
que oferecem cPanel ou Plesk.
Dos mais variados servios existentes no mercado, ns escolhemos a Digital Ocean por
possuir uma interface simples de administrao e um preo bom para o plano mais simples
(atualmente 5 dlares). Tambm existe um cupom de desconto que lhe dar $10.00 dlares em
crdito. Desta forma, voc poder usar o servio da Digital Ocean com dois meses gratuitos.
Nesta obra, criaremos o domnio practicalangular2.com, voc deve trocar para o seu domnio
sempre que for necessrio. Usamos o servio name.com para criar e gerenciar domnios, caso
queira us-lo tambm, use o cupom https://www.name.com/referral/2794d9 para ganhar
$5.00 em crditos na criao do seu prprio domnio. Pode-se criar qualquer domnio, no
site que voc est acostumado a registr-los.

11.1 Criando a conta na Digital Ocean

O primeiro passo para criar uma conta na Digital Ocean usar o cupom de desconto, clicando
no link https://m.do.co/c/0812e52d3f24. Aps clicar no link, clique no boto Sign Up para
https://www.name.com/referral/2794d9
https://m.do.co/c/0812e52d3f24
Publicando a aplicao em um servidor cloud 198

criar a sua conta. Aps fornecer o seu email e senha, surge a tela de configurao semelhante
a exibida a seguir:

Nesta tela voc ir confirmar o seu email, depois atualizar as suas informaes de pagamento
(necessita carto de crdito ou paypal) e ento clicar no boto Create Droplet. Na Digital
Ocean, um droplet um servidor que estar sempre ativo, e ser nele que iremos publicar a
aplicao.

11.2 Criando o droplet (servidor)

Clique no boto Create Droplet para iniciar o processo de criao do servidor. A primeira
escolha a fazer sobre a imagem do servidor, ou seja, qual distribuio iremos usar. Escolha
a verso Ubuntu 15.10 x64, conforme a figura a seguir:
Publicando a aplicao em um servidor cloud 199

Aps escolher a distribuio, escolha o preo. Vamos optar pelo mas barato, de $5.00, com
isso pode-se testar o servio por dois meses:

O prximo passo escolher o local onde o servidor ser instalado. Escolha de acordo com
a sua regio mais prxima. Em Select additional options e Add your SSH keys deixe o
valor padro.
No item How many Droplets? escolha 1 Droplet e no item Choose a hostname voc dever
escolher o nome do seu servidor. No necessrio inserir o nome do domnio, ento
Publicando a aplicao em um servidor cloud 200

deixaremos o valor padro, conforme a imagem a seguir:

Clique no boto Create para criar o seu servidor. Aguarde alguns minutos e verifique na sua
caixa de email informaes sobre o servidor recm criado, como a senha de root e o seu ip.

11.3 Configurando o acesso SSH

Aps criar o servidor, voc receber um email com informaes como o IP Adress, username
e password. Voc usar estas informaes para realizar uma conexo ssh no servidor.
Para usurios Windows, recomendamos a instlao do programa Putty. Para usurios Linux,
o acesso SSH realizado atravs da linha de comando ssh user@ip. Como usurio Linux
sabemos que voc possui o conhecimento necessrio para operar o SSH, ento vamos da um
foco maior aos usurios Windows.
Aps instalar o Putty, abra-o para ter uma interface semelhante a figura a seguir:
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
Publicando a aplicao em um servidor cloud 201

No campo host name (or ip adress), insira o ip do seu servidor (est no email que a
Digital Ocean lhe enviou ao criar o droplet). Em Port deixe a 22, que a porta padro
de conexo SSH. Clique no boto Open e clique em Yes na mensagem que surge pelo Putty.
Surge ento a tela de login do seu servidor, no qual voc deve informar o login e a senha que
est no email.

Dica: Copie a senha e cole no putty usando o boto direito do mouse. Basta clicar
uma vez no boto direito do mouse para automaticamente colar o texto.

Aps logar, ser necessrio redefinir a sua senha de root. use uma senha forte com letras e
nmeros, pois o usurio root tem controle total sobre o seu servidor. O resultado do login
at a mudana de senha semelhante a figura seguir:
Publicando a aplicao em um servidor cloud 202

11.4 Criando o usurio

A primeira ao deve ser feita no novo servidor criar um usurio com um acesso mais
restrito ao sistema. Ser neste usurio que incluiremos tambm o sistema blog que criamos
no captulo 8.
Para incluir um usurio, digite:

# adduser username
Publicando a aplicao em um servidor cloud 203

Pode-se usar o nome de usurio que desejar, insira o seu nome por exemplo. Nesta
obra, usaremos username.

Aps criar o usurio, vamos dar um pouco de poderes a ele pelo comando sudo. Se voc no
sabe o que sudo, verifique neste link o seu significado.

# adduser username sudo


Adding user 'username' to group 'sudo'
Done.

Com o usurio criado, podemos relogar com ele. Feche o putty (ou digite exit) e logue
novamente, agora com o usurio que acabou de criar:
https://en.wikipedia.org/wiki/Sudo
Publicando a aplicao em um servidor cloud 204

Atravs deste usurio faremos todas as alteraes no servidor necessrias para que possamos
instalar a aplicao blog.

11.5 Instalando o git

Usaremos o git para obter o cdigo fonte da aplicao blog. Para instalar o git, faa:

$ sudo apt-get install git

Aps instalar o git, podemos obter o cdigo fonte da aplicao com o seguinte comando:

$ git clone https://github.com/danielschmitz/angular2-codigos.git

Todo o cdigo fonte da obra ser baixado, mas precisamos apenas do diretrio blog que est
no captulo 8. Vamos copiar o diretrio blog para o diretrio raiz do usurio. Para fazer isso,
execute o seguinte comando:
Publicando a aplicao em um servidor cloud 205

$ cp angular2-codigos/08/blog /home/username/ -R

A aplicao blog na qual queremos publicar estar no diretrio /home/username/blog,


conforme a figura a seguir:

11.6 Instalando Node

O node ainda no est instalado no servidor. Para a sua instalao, use o seguinte comando:

$ apt-get install curl


$ curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash -
$ sudo apt-get install --yes nodejs

Aps a instalao do node, devemos executar o seguinte comando:

$ sudo ln -s /usr/bin/nodejs /usr/bin/node

Este comando cria um link simblico de nodejs para node.

11.7 Instalando o nginx

Em sua definio mais simples, o nginx um servidor web capaz de processar as requisies
do servidor. Usaremos o nginx em conjunto com o node. Para instalar o nginx, faa:
Publicando a aplicao em um servidor cloud 206

$ sudo apt-get install nginx

Aps a instalao, precisamos configurar o nginx como um servio do servidor. Ou seja,


ele precisa estar ativo quando o servidor for reiniciado. O Ubuntu 15 (e a maioria das
distribuies linux) usa o sistema systemctl para isso, e para ativ-lo, devemos executar os
seguintes comandos:

$ sudo systemctl enable nginx


$ sudo systemctl start nginx

Aps essa configurao, pode-se verificar se o servio nginx est ativo pelo comando:

$ ps aux | grep nginx

Os processos sero exibidos, conforme a figura a seguir:

Neste ponto pode-se realizar um teste no navegador, bastando acessar o ip do servidor, como
no exemplo a seguir:
Publicando a aplicao em um servidor cloud 207

11.8 Instalando os mdulos do node


Como foi abordado nos captulos anteriores, o arquivo package.json contm as informaes
sobre o projeto, dentre elas das suas dependncias. Para instalar as dependncias do projeto
blog, devemos executar o seguinte comando:

$ cd /home/username/blog
$ npm install

Aps executar o npm install, verifique que o diretrio node_modules foi criado, e as
bibliotecas adicionadas.

11.9 Recompilando os arquivos TypeScript


Vamos recompilar os arquivos TypeScript para javascript. Primeiro, devemos adicionar o
typeScript no servidor de forma global, com o seguinte comando:

$ sudo npm install typescript -g


$ cd /home/username/blog
$ tsc

Os arquivos TypeScript so recompilados e a mensagem Compilation complete. Watching


for file changes. surge caso o tsconfig.json esteja com a opo watch=true.
Publicando a aplicao em um servidor cloud 208

11.10 Teste inicial

Para testar a aplicao no navegador, execute o seguinte comando:

$ cd /home/username/blog
$ node server.js

A mensagem Listem 8080 surgir, indicando que o servidor express est funcionando na
porta 8080. Isso significa que podemos acessar a aplicao atravs do ip e sua porta, conforme
a imagem a seguir:

11.11 Integrao entre nginx e node

J sabemos que o node pode ser executado via linha de comando, atravs do node server.js
foi possvel fazer com que a aplicao blog fosse acessada. Mas o nosso objetivo realizar
uma integrao entre o nginx e o node, e fazer com que a porta 80, que a porta padro para
acesso http, use o node.
Para isso, preciso realizar dois procedimentos:
1- Adicionar o node server.js como um servio do servidor 2- Configurar o nginx para
executar este servio
Publicando a aplicao em um servidor cloud 209

Primeiro, vamos adicionar o node como um servio do servidor. Isso far com que ele seja
executado quando a mquina religada, ou quando algum problema ocorre no node, fazendo
com que o servio seja reexecutado.
Como estamos usando o Ubuntu 15, usamos novamente o systemd para adicionar este servio.
Atravs do editor de textos nano, vamos adicionar o seguinte arquivo:

$ sudo nano /etc/systemd/system/node-app-1.service

Com o nano aberto, copie este cdigo e cole:

[Service]
ExecStart=/usr/bin/node /home/username/blog/server.js
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=node-app-1
User=username
Group=username
Environment=NODE_ENV=production PORT=5000

[Install]
WantedBy=multi-user.target

Este arquivo node-app-1.service uma configurao que ir, de acordo com o parmetro
ExecStart executar o comando /usr/bin/node /home/username/blog/server.js. Outros
parmetros so adicionados, como por exemplo o Enviroment=NODE_ENV=production, que
pode ser usado na sua aplicao.
Outro parmetro importante PORT=5000, configurando a porta do servio. Se observar no
arquivo server.js a definio da porta feita pelo cdigo var port = process.env.PORT
|| 8080, neste momento a porta 5000 ser utilizada.

Com o arquivo criado, podemos iniciar e ativar o servio, atravs do seguinte comando:

$ sudo systemctl start node-app-1


$ sudo systemctl enable node-app-1

Agora o servio node-app-1 est ativo. Pode-se verificar isso atravs do seguinte comando:
Publicando a aplicao em um servidor cloud 210

$ sudo systemctl status node-app-1

Atravs deste comando, tem-se a seguinte resposta:

Pode-se testar tambm atravs do navegador, acessando o ip do servidor e a porta 5000.


Com a primeira parte pronta, temos o servio node sendo executado na porta 5000. Precisamos
agora ativar o nginx e fazer o que chamamos de proxy, isso , fazer com que quando a porta
80 for chamada, o nginx direcione para a porta 5000.
Para isso vamos reescrever o comportamento do site padro do nginx. Execute o seguinte
comando:

$ sudo mv /etc/nginx/sites-available/default /etc/nginx/sites-available/def\


ault-original
$ sudo nano /etc/nginx/sites-available/default

No nano, adicione a seguinte configurao:

upstream node_server {
server 127.0.0.1:5000 fail_timeout=0;
}

server {
listen 80 default_server;
listen [::]:80 default_server;

index index.html index.htm;

server_name _;
Publicando a aplicao em um servidor cloud 211

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://node_server;
}
}

Nesta configurao, usamos o comando upstream para criar um servidor chamado node_-
server. Este servidor ir apontar para a prpria mquina na porta 5000, a mesma que
configuramos no servio node-app-1.
O servidor principal est escutando a porta 80, e definimos atravs do location / o
proxy para o servidor node_server. Atravs desta configurao, fazemos que com que o
servidor ngix escute a porta 80 e faa um proxy a porta 5000, executando assim o node e
consequentemente o express.
Aps alterar a configurao, precisamos reiniciar o nginx com o seguinte comando:

$ sudo systemctl restart nginx

Com o nginx reiniciado, podemos finalmente acessar a aplicao somente com o ip do


servidor, conforme a figura a seguir:
Publicando a aplicao em um servidor cloud 212

11.12 Algumas consideraes sobre node+nginx

importante frisar que esta configurao visa dar um passo inicial ao seu estudo sobre
o gerenciamento de sistemas com node e nginx. Existem pontos extras que precisam ser
reavaliados para tornar a sua aplicao mais robusta. Por exemplo, requisies estticas
neste momento esto sendo processadas pelo Node atravs do express.static, mas o melhor
caminho configurar o nginx para gerenciar estas requisies, ao invs do node. Conexes
SSL tambm necessitam ser gerenciadas pelo nginx. Estas configuraes envolvem passos
extras que no sero abordados nesta obra. Nosso objetivo mostrar que podemos criar
aplicaes em node e disponibiliz-las na web.

11.13 Domnio

Se voc criou um domnio para a sua aplicao, chegou o momento de configur-lo. Para isso,
acesse o painel de administrao do seu domnio, que varia de acordo com o seu provedor.
Usamos aqui o name.com, que vc pode adquirir um cupom de $5.00 nesta url.
Aps criar o domnio, acesse o painel de DNS RECORDS, conforme a figura a seguir:
https://www.name.com/referral/2794d9
Publicando a aplicao em um servidor cloud 213

Na tela Edit DNS Record, adicione duas entradas informando o ip do servidor que a Digital
Ocean criou para voc, da seguinte forma:

Com estas duas entradas, aguarde algumas horas para a publicao DNS ocorrer e acesse o
domnio que voc criou, no mais o IP. O blog que criamos em nossa obra ser carregado:
Publicando a aplicao em um servidor cloud 214

Voc pode testar o blog neste momento, acessando http://www.practicalangular2.com/

11.14 Concluso

Aps criarmos a aplicao em nosso ambiente de desenvolvimento, conseguimos executar


todos os passos necessrios para ter a mesma aplicao no servidor de produo, ligando um
domnio ao servidor que criamos pela Digital Ocean, e usando nginx+node para hospedar a
aplicao.
Como estamos publicando a obra pela Leanpub, possvel estender o livro com mais
contedo, mas para isso precisamos do feedback da comunidade. Acesse a pgina desta obra
em https://leanpub.com/livro-angular2 e clique em Discuss this Book.

http://www.practicalangular2.com/

Вам также может понравиться