Usando Services e HTTP em Angular 2

Olá, no último post sobre Angular 2 vimos como configurar rotas. Hoje veremos como usar services com requisições HTTP, fazendo um exemplo simples que consome uma API Node.js com banco de dados SQLite.

Downloads

A única coisa que vamos precisar baixar é o bootstrap.

Estrutura da aplicação

Nossa aplicação terá uma estrutura simples:

asd.fw

API

package.json

Como eu disse antes será uma API simples, que estará no arquivo server.js, mas antes disso vamos criar nosso arquivo package.json onde teremos as dependências.

{
  "name": "angular2-services-http",
  "version": "1.0.0",
  "description": "Exemplo de como usar services em Angular2",
  "main": "server.js",
  "scripts": {
    "test": "node server"
  },
  "dependencies":{
    "express":"latest",
    "sqlite-sync":"latest",
    "body-parser":"latest"
  }
}

Depois de ter criado esse arquivo na pasta raiz da sua aplicação, execute o seguinte comando:

$ npm install

Para instalar as dependências. Note que todos os pacotes instalados estão na versão mais recente (latest), você pode mudar para a versão que preferir de cada um.

server.js

Nesse arquivo estará a nossa API, que deve ter os métodos HTTP GET, POST, PUT e DELETE, para listar, cadastrar, editar e excluir pessoas.

Nele também estará nossa conexão com o banco de dados, na qual usamos o módulo sqlite-sync que funciona de forma síncrona ou assíncrona. Veja mais detalhes sobre ele aqui. O arquivo de banco de dados será criado automaticamente pelo módulo dentro da pasta model, caso não exista.

Vamos ao arquivo:

var express = require('express'),
	app = express(),
	router = express.Router(),
	bodyParser = require('body-parser'),
	path = require('path'),
	sqlite = require('sqlite-sync');

sqlite.connect('./model/database.db');

sqlite.run("CREATE TABLE pessoas (id INTEGER PRIMARY KEY AUTOINCREMENT, nome CHAR(100), email CHAR(100));");

var exec = require('child_process').exec;

app.use(bodyParser.json());

app.use('/app', express.static(path.join(__dirname,'/app')));
app.use('/bootstrap', express.static(path.join(__dirname,'/bootstrap')));
app.use('/angular2', express.static(path.join(__dirname,'/angular2')));

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname, 'index.html'));
});

app.get('/api/pessoas', function(req,res){
	res.send(sqlite.run("SELECT * FROM pessoas"));
});

app.post('/api/pessoas', function(req, res){
	sqlite.insert('pessoas', req.body, function(id){
		res.send({'id':id});	
	});
});

app.put("/api/pessoas/:id", function(req, res){
	var id = req.params.id;
	var body = req.body;
	sqlite.update('pessoas', body, {id:id}, function(result){
		res.send({result : result});
	});
});

app.delete('/api/pessoas/:id', function(req, res){
	var id = req.params.id;
	sqlite.delete('pessoas',{id: id}, function(result){
		res.send({result : result});
	});
});

app.listen(3000, function(){
	exec('start http://localhost:3000');
});

Note que na linha 10 criamos a tabela no banco de dados. Você pode fazer isso por meio de outro aplicativo SGBD se quiser, como SQLite Studio por exemplo.

Aplicação

Agora vamos à aplicação que vai consumir a API, conforme estrutura de pastas e arquivos mostrada mais acima. Nossa aplicação terá apenas uma única página e não precisa de rotas.

index.html

Vamos começar pelo arquivo principal da aplicação, que deve conter as configurações para uso do TypeScript com SystemJS, como visto no post TypeScript – executando no browser com SystemJS.

<!DOCTYPE html>
<html>
<head>
  <script>document.write('<base href="' + document.location + '" />');</script>
  <title>Angular2 - Service HTTP</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" type="text/css" href="bootstrap/css/bootstrap.css">
  <!-- jQuery -->
  <script src="http://code.jquery.com/jquery-1.12.0.min.js"></script>
  <!-- Bootstrap -->
  <script src="bootstrap/js/bootstrap.js"></script>

  <!-- IE required polyfills, in this exact order -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.0/es6-shim.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.26/system-polyfills.js"></script>
  <script src="https://npmcdn.com/angular2@2.0.0-beta.17/es6/dev/src/testing/shims_for_IE.js"></script>

  <script src="https://code.angularjs.org/2.0.0-beta.17/angular2-polyfills.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.26/system.js"></script>
  <script src="https://npmcdn.com/typescript@1.8.10/lib/typescript.js"></script>
  <script src="https://code.angularjs.org/2.0.0-beta.17/Rx.js"></script>
  <script src="https://code.angularjs.org/2.0.0-beta.17/angular2.dev.js"></script>
  
  <script src="https://code.angularjs.org/2.0.0-beta.17/http.dev.js"></script>

  <script>
  System.config({
        transpiler: 'typescript', 
        typescriptOptions: { emitDecoratorMetadata: true }, 
        packages: {'app': {defaultExtension: 'ts'}} 
      });
      System.import('app/main')
            .then(null, console.error.bind(console));
  </script>
</head>

<body>
  <my-app>Loading...</my-app>
</body>
</html>

Na linha 24 é importado o arquivo http.dev.js, que possibilita o uso das diretivas HTTP.

app/main.ts

Este arquivo inicia nossa aplicação Angular 2.

import { bootstrap }    from 'angular2/platform/browser';
import 'rxjs/Rx';
import { HTTP_PROVIDERS } from 'angular2/http';
import { AppComponent } from './app.component';

bootstrap(AppComponent, [HTTP_PROVIDERS]);

Na linha 3 importamos os HTTP_PROVIDERSo que nos possibilita o uso de requisições HTTP.

app/app.component.ts

Nosso componente principal, tem a função de controlar o html, criando nossa aplicação na tag informada como seletor.

import { Component, Input} from 'angular2/core';
import { HTTP_PROVIDERS }    from 'angular2/http';

// Services
import { PessoaService } from './pessoa.service';

@Component({
	selector:    'my-app',
	templateUrl: 'app/view.html',
	providers: [
		PessoaService,
		HTTP_PROVIDERS
	]
})

/**
* Classe AppComponent
*/
export class AppComponent {
	/**
	* Atributos
	*/
	private id: number;
	private nome, email: string;
	private pessoas: Array[];
	private pessoa: AppComponent = {};

	/**
	* Método construtor
	* @param _service: PessoaService
	*/
	constructor(private _service: PessoaService){
		this.getPessoas();
	}

	/**
	* Listando pessoas
	*/
	getPessoas(){
		this._service.getPessoas()
      		.then(pessoas => {this.pessoas = pessoas});
	}

	/**
	* Salvar pessoa
	*/
	salvar(){
		if(this.pessoa.id){
			this._service.editar(this.pessoa).then(res => {
				this.getPessoas();
				$('#myModal').modal('hide');
			});
		}else{
			this._service.novo(this.pessoa).then(res => {
				this.getPessoas();
				$('#myModal').modal('hide');
			});
		}
	}

	/**
	* Editar pessoa
	* @param item: Array
	*/
	editar(item){
		this.pessoa = item;
		$('#myModal').modal('show');
	}

	/**
	* Excluir pessoa
	* @param item: Array
	*/
	excluir(item){
		if(confirm("Você tem certeza que deseja excluir?")){
			this._service.excluir(item.id).then(res => {
				this.getPessoas();
			});
		}
	}

	/**
	* Cancelar Cadastro
	*/
	cancelar(){
		this.pessoa = {};
		$('#myModal').modal('hide');
	}
}

Note que na linha 5 importamos o service do arquivo pessoa.service.ts que é onde teremos as requisições HTTP.

app/pessoa.service.ts

Nosso service, que usando da classe Http realiza GET, POST, PUT e DELETE.

 

import {Injectable}     from 'angular2/core';
import {Http, Headers,RequestOptions } from 'angular2/http';

@Injectable()

/**
* Service Pessoa
*/
export class PessoaService {

	private apiUrl = 'api/pessoas';  // URL para web api

	/**
	* Método construtor
	* @param http: Http
	*/
	constructor(private http: Http) { }

	/**
	* Listando pessoas
	*/
	getPessoas(){
	 	return this.http.get(this.apiUrl)
		 	.toPromise()
		 	.then(response => response.json())
		 	.catch(this.handleError);
	}

	/**
	* Nova pessoa
	* @param pessoa: Array
	* @return http POST
	*/
	novo(pessoa: Array){
	 	let body = JSON.stringify(pessoa);
	 	let headers = new Headers({'Content-Type': 'application/json'});
	 	let options = new RequestOptions({ headers: headers });

	 	return this.http.post(this.apiUrl, body, options)
		 	.toPromise()
		 	.then(res => res.json())
		 	.catch(this.handleError);
	}

	/**
	* Editar pessoa
	* @param pessoa: Array
	* @return http PUT
	*/
	editar(pessoa: Array){
	 	let id = pessoa.id;
	 	delete pessoa.id;
	 	let body = JSON.stringify(pessoa);
	 	let headers = new Headers({ 'Content-Type': 'application/json' });
	 	let options = new RequestOptions({ headers: headers });

	 	let url = this.apiUrl + '/' + id;

	 	return this.http.put(url, body, options)
		 	.toPromise()
		 	.then(res => res.json())
		 	.catch(this.handleError);
	}

	/**
	* Excluir pessoa
	* @param id: number
	* @return http DELETE
	*/
	excluir(id: number){
	 	let url = this.apiUrl + '/' + id;
	 	return this.http.delete(url)
		 	.toPromise()
		 	.then(res => res.json().data)
		 	.catch(this.handleError);
	}
}

app/view.html

Arquivo HTML que será controlado pelo nosso componente Angular2.

<div class="container">
	<h2>Cadastro de Pessoas</h2>
	<hr>
	<div class="row">
		<div class="col-md-6">
			<button class="btn btn-primary" data-toggle="modal" data-target="#myModal"><i class="fa fa-plus"></i> Novo</button>	
		</div>
	</div>
	<hr>
	<div class="row">
		<div class="col-md-12">
			<table class="table">
				<thead>
					<tr>
						<th>#</th>
						<th>Name</th>
						<th>E-mail</th>
						<th></th>
					</tr>
				</thead>
				<tbody>
					<tr *ngFor="let pessoa of pessoas">
						<td>{{pessoa.id}}</td>
						<td>{{pessoa.nome}}</td>
						<td>{{pessoa.email}}</td>
						<td>
							<button (click)="editar(pessoa)" class="btn btn-xs btn-info">Editar</button>
							<button (click)="excluir(pessoa)" class="btn btn-xs btn-danger">Excluir</button>
						</td>
					</tr>
				</tbody>
			</table>
		</div>
	</div>
</div>

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
	<div class="modal-dialog" role="document">
		<div class="modal-content">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
				<h4 class="modal-title" id="myModalLabel">Cadastro</h4>
			</div>
			<div class="modal-body">
				<div class="form-group">
					<label>Nome:</label>
					<input type="text" class="form-control" [(ngModel)]="pessoa.nome">
				</div>
				<div class="form-group">
					<label>E-mail:</label>
					<input type="email" class="form-control" [(ngModel)]="pessoa.email" >
				</div>
			</div>
			<div class="modal-footer">
				<button type="button" class="btn btn-default" (click)="cancelar()" >Cancelar</button>
				<button type="button" class="btn btn-primary" (click)="salvar()">Salvar</button>
			</div>
		</div>
	</div>
</div>

Executando

Para executar sua aplicação rode o seguinte comando no bash, prompt ou terminal:

$ npm test

Ou

$ node server

Concluindo

Este é o terceiro post da série sobre Angular2. Você pode ter acesso ao código fonte no Git Hub. Até a próxima.

Jayr Alencar

Doutorando em Ciências da Computação no Centro de Informática da Universidade Federal do Pernambuco (CIn - UFPE); Mestre pela mesma instituição; Formado em Análise e Desenvolvimento de Sistemas; Católico; Fã de O Senhor do Anéis.

Você pode gostar...

1 Resultado

  1. Sergio Nhaca disse:

    Boa tarde
    Achei o artigo bem resumido e pratico.
    Sou novo no angular e tenho tentado implementar um exemplo que fiz com spring mvc, é o seguinte
    Não consigo implememntar uma venda com itens por exemplo
    cliente: joao
    produto: cerveja x
    quantidade: 2
    valor: 20
    Quero salvar o cliente na tabela vendas e o produto na tabela itens.
    Obrigado

Deixe um comentário para Sergio Nhaca Cancelar resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *