Angular
10/25/2018

Como criar CRUD com Angular e Firebase Realtime Database – Em alguns simples passos

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

  1. Instalar o Firebase no projeto
  2. Criar os componentes, services e classes
  3. Criar a classe que vai ter os dados do contato
  4. Criar o service que vai compartilhar o contato entre os dois componentes
  5. Criar o service que fará o CRUD
  6. Criar o formulário de cadastro
  7. 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>

Referências