Nessa vídeo aula eu mostro como criar um CRUD (CRUD significa, em inglês, Create, Read, Update e Delete e em português é Incluir, Alterar, Excluir e Consultar) com Angular e Firebase Realtime Database.
O que é o Firebase Realtime Database
O Firebase Realtime Database é um banco de dados NoSQL hospedado na nuvem. Com ele, você armazena e sincroniza dados entre os seus usuários em tempo real.
Para saber mais você pode acessar diretamente a página do Firebase clicando aqui.
Pré requisitos
Ter um projeto já criado no console do Firebase e com as permissões de leitura e escrita habilitadas. (Isso é mostrado no vídeo)
Esse tutorial está utilizando as seguintes versões das dependências:
- Angular: 7.0
- Firebase: 5.5.5
- AngularFire2: 5.1.0
Passo a passo para o CRUD
- Instalar o Firebase no projeto
- Criar os componentes, services e classes
- Criar a classe que vai ter os dados do contato
- Criar o service que vai compartilhar o contato entre os dois componentes
- Criar o service que fará o CRUD
- Criar o formulário de cadastro
- Criar a lista de contatos
1 – Instalar o Firebase no projeto
Para fazer a integração do Firebase com o Angular é necessário usar uma biblioteca desenvolvida pelo próprio time do Angular que se chama AngularFire2.
Para instalar, basta rodar o comando abaixo que vai instalar a exata versão do Firebase e AngularFire2 usada nesse tutorial
npm install firebase@5.5.5 @angular/fire@5.1.0 --save
Próximo passo é adicionar as configurações do Firebase no arquivo environment.ts. Essas configurações podem ser obtidas na página do projeto.
firebase: {
apiKey: "[SUA KEY]",
authDomain: "[SEU AUTH DOMAIN]",
databaseURL: "[SUA DATABASE URL]",
projectId: "[SEU PROJECT ID]",
storageBucket: "[SEU STORAGE BUCKET]",
messagingSenderId: "[SUA MESSAGING SENDER ID]"
}
Feito isso, agora é necessário importar no app.module os módulos do AngularFire2 que serão usados. Nesse tutorial será usado apenas o modulo do Firebase Realtime Database.
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { AngularFireModule } from '@angular/fire'; import { AngularFireDatabaseModule } from '@angular/fire/database'; import { environment } from '../environments/environment'; import { EditComponent } from './contatos/edit/edit.component'; import { ListComponent } from './contatos/list/list.component'; @NgModule({ declarations: [ AppComponent, EditComponent, ListComponent ], imports: [ BrowserModule, FormsModule, AppRoutingModule, AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
2 – Criar os componentes, services e classes
O projeto será um CRUD de contatos com nome e telefone, para isso é necessário criar um componente para o formulário e outro para a lista de contatos. Alem disso será criado o service que fará o crud no Firebase.
Basta rodar os comandos abaixo para a criação dos componentes, services e classes.
ng g component contatos/edit ng g component contatos/list ng g service contatos/shared/contato ng g service contatos/shared/contato-data ng g class contatos/shared/contato
3 – Classe com os dados do contato
O arquivo contato.ts deve ficar com o conteúdo abaixo.
export class Contato { nome: string = ''; telefone: string = ''; }
4 – Service para compartilhar o contato entre os componentes
Durante a alteração de um contato, é necessário enviar o contato que está sendo editado para o componente de formulário.
Para isso o o arquivo contato-data.service.ts deve ficar com o conteúdo abaixo.
Como o foco do tutorial é mostrar o CRUD, esse arquivo não será explicado aqui mas ele é explicado no vídeo.
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { Contato } from './contato'; @Injectable({ providedIn: 'root' }) export class ContatoDataService { private contatoSource = new BehaviorSubject({ contato: null, key: '' }); currentContato = this.contatoSource.asObservable(); constructor() { } changeContato(contato: Contato, key: string) { this.contatoSource.next({ contato: contato, key: key }); } }
5 – Service responsável pelo CRUD.
O service tem 4 métodos: Inclusão, alteração, consulta e exclusão.
Para incluir um dado no Firebase é necessário acessar o nó onde os dados serão salvos e executar o método push passando como parâmetro o dado que deve ser incluído, conforme abaixo.
Método para incluir um registro
insert(contato: Contato) { this.db.list('contato').push(contato) .then((result: any) => { console.log(result.key); }); }
Para alterar um dado no Firebase, é necessário acessar o nó onde os dados serão salvos e executar o método update passando como parâmetro a key do objeto e o dados que deve ser alterado, conforme abaixo.
update(contato: Contato, key: string) { this.db.list('contato').update(key, contato) .catch((error: any) => { console.error(error); }); }
Para buscar uma lista de dados no Firebase, é necessário acessar o nó onde os dados estão e mapear da maneira que você quer acessar as propriedades desse objeto para mostrar na tela, conforme abaixo.
getAll() { return this.db.list('contato') .snapshotChanges() .pipe( map(changes => { return changes.map(c => ({ key: c.payload.key, ...c.payload.val() })); }) ); }
E por fim, para excluir, basta acessar o nó do objeto e executar o método remove, conforme abaixo.
delete(key: string) { this.db.object(`contato/${key}`).remove(); }
O arquivo contato.service.ts com todos os métodos explicados acima deve ficar conforme abaixo.
import { Injectable } from '@angular/core'; import { AngularFireDatabase } from '@angular/fire/database'; import { Contato } from './contato'; import { map } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class ContatoService { constructor(private db: AngularFireDatabase) { } insert(contato: Contato) { this.db.list('contato').push(contato) .then((result: any) => { console.log(result.key); }); } update(contato: Contato, key: string) { this.db.list('contato').update(key, contato) .catch((error: any) => { console.error(error); }); } getAll() { return this.db.list('contato') .snapshotChanges() .pipe( map(changes => { return changes.map(c => ({ key: c.payload.key, ...c.payload.val() })); }) ); } delete(key: string) { this.db.object(`contato/${key}`).remove(); } }
6 – Formulário de cadastro
Para salvar os contatos no Firebase o formulário criado nesse tutorial fica conforme abaixo
edit.component.ts
import { Component, OnInit, Input } from '@angular/core'; import { Contato } from '../shared/contato'; import { ContatoService } from '../shared/contato.service'; import { ContatoDataService } from '../shared/contato-data.service'; @Component({ selector: 'app-edit', templateUrl: './edit.component.html', styleUrls: ['./edit.component.scss'] }) export class EditComponent implements OnInit { contato: Contato key: string = ''; constructor(private contatoService: ContatoService, private contatoDataService: ContatoDataService) { } ngOnInit() { this.contato = new Contato(); this.contatoDataService.currentContato.subscribe(data => { if (data.contato && data.key) { this.contato = new Contato(); this.contato.nome = data.contato.nome; this.contato.telefone = data.contato.telefone; this.key = data.key; } }) } onSubmit() { if (this.key) { this.contatoService.update(this.contato, this.key); } else { this.contatoService.insert(this.contato); } this.contato = new Contato(); } }
edit.component.html
<form (ngSubmit)="onSubmit()"> <div class="form-group"> <label>Nome</label> <input type="text" class="form-control" [(ngModel)]="contato.nome" name="nome" /> </div> <div class="form-group"> <label>Telefone</label> <input type="tel" class="form-control" [(ngModel)]="contato.telefone" name="telefone" /> </div> <button type="submit" class="btn btn-primary">Salvar</button> </form>
7 – Listagem de contato
Para exibir os contatos cadastrados na tela, o componente criado nesse tutorial fica conforme abaixo.
list.component.ts
import { Contato } from './../shared/contato'; import { Component, OnInit } from '@angular/core'; import { ContatoService } from '../shared/contato.service'; import { Observable } from 'rxjs'; import { ContatoDataService } from '../shared/contato-data.service'; @Component({ selector: 'app-list', templateUrl: './list.component.html', styleUrls: ['./list.component.scss'] }) export class ListComponent implements OnInit { contatos: Observable<any>; constructor(private contatoService: ContatoService, private contatoDataService: ContatoDataService) { } ngOnInit() { this.contatos = this.contatoService.getAll(); } delete(key: string) { this.contatoService.delete(key); } edit(contato: Contato, key: string) { this.contatoDataService.changeContato(contato, key); } }
list.component.html
<div class="card mt-2" *ngFor="let contato of contatos | async"> <div class="card-body"> <h5 class="card-title">{{contato.nome}}</h5> <p class="card-text">{{contato.telefone}}</p> </div> <div class="card-footer"> <button type="button" class="btn btn-default" (click)="edit(contato, contato.key)">Editar</button> <button type="button" class="btn btn-danger ml-2" (click)="delete(contato.key)">Excluir</button> </div> </div>
Referencias
- Firebase: https://firebase.google.com/
- AngularFire2: https://github.com/angular/angularfire2