Como criar um CRUD com Ionic e Firebase – 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 Ionic e Firebase Realtime Database usando a nova versão do AngularFire2 (5.0.0). 

Mostro também diferentes maneiras de salvar um objeto e de fazer algumas queries simples.

 

Esse tutorial está utilizando as seguintes versões das dependências:

  • Ionic: 3.18.0
  • AngularFirebase2: 5.0.0-rc.3
  • Firebase: 4.6.2

 

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.

 

Criando uma aplicação de exemplo

Será criado uma aplicação para castro de contato com nome e telefone.

O passo a passo abaixo é o mesmo mostrado no vídeo.

  • Passo 1: Criar o aplicativo.
  • Passo 2: Instalar as dependências (AngularFire2 e Firebase).
  • Passo 3: Criar o provider para fazer o CRUD de contatos.
  • Passo 4: Ajustar a pagina home para exibir os contatos cadastrados.
  • Passo 5: Criar a pagina para inclusão/alteração de contatos.

 

Passo 1: Criar o aplicativo

ionic start NOME_DO_APP blank

Criar o provider e as páginas

ionic g provider contact
ionic g page contact-edit

 

Passo 2: Instalar as dependências (AngularFire2 e Firebase)

npm install firebase angularfire2 --save

Arquivo no app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';

import { AngularFireModule } from 'angularfire2';
import { AngularFireDatabaseModule } from 'angularfire2/database';

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { ContactProvider } from '../providers/contact/contact';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    AngularFireModule.initializeApp({
      apiKey: "SEU API KEY",
      authDomain: "SEU AUTH DOMAIN",
      databaseURL: "SUA DATABASE URL",
      projectId: "SEU PROJECT ID",
      storageBucket: "SEU STORAGE BUCKET",
      messagingSenderId: "SEU MESSAGING SENDER ID"
    }),
    AngularFireDatabaseModule
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    ContactProvider
  ]
})
export class AppModule {}

 

Passo 3: Criar o provider para fazer o CRUD de contatos

Arquivo providers/contact/contact.ts

import { Injectable } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';

@Injectable()
export class ContactProvider {
  private PATH = 'contacts/';

  constructor(private db: AngularFireDatabase) {
  }

  getAll() {
    return this.db.list(this.PATH, ref => ref.orderByChild('name'))
      .snapshotChanges()
      .map(changes => {
        return changes.map(c => ({ key: c.payload.key, ...c.payload.val() }));
      })
  }

  get(key: string) {
    return this.db.object(this.PATH + key).snapshotChanges()
      .map(c => {
        return { key: c.key, ...c.payload.val() };
      });
  }

  save(contact: any) {
    return new Promise((resolve, reject) => {
      if (contact.key) {
        this.db.list(this.PATH)
          .update(contact.key, { name: contact.name, tel: contact.tel })
          .then(() => resolve())
          .catch((e) => reject(e));
      } else {
        this.db.list(this.PATH)
          .push({ name: contact.name, tel: contact.tel })
          .then(() => resolve());
      }
    })
  }

  remove(key: string) {
    return this.db.list(this.PATH).remove(key);
  }
}

 

Salvando objetos

Abaixo vou explicar 2 maneiras diferente para salvar um objeto:

1 – Usando a lista: 

this.db.list('CAMINHO')
  .update(contact.key, { name: contact.name, tel: contact.tel })
  .then(() => resolve())
  .catch((e) => reject(e));

Observe que no exemplo acima, no método “update” é necessário passar a chave do objeto que será atualizado.

 

2 – Usando o objeto:

this.db.object('CAMINHO' + contact.key)
  .update({ name: contact.name, tel: contact.tel })
  .then(() => resolve())
  .catch((e) => reject(e));

Observe que no exemplo acima, no método “update” eu não preciso da key do objeto pois ela é usada para compor o caminho até no objeto

 

3 – Diferença entre set e update

Nos dois exemplos acima é possível utilizar o método “set” no lugar do “update”, a grande diferença entre os dois é:

  • Set: Substitui o objeto inteiro no servidor pelo valor enviado.
  • Update: Substitui apenas os valores que estão sendo enviados.

 

Passo 4: Ajustar a pagina home para exibir os contatos cadastrados

Arquivo home.ts

import { ContactProvider } from './../../providers/contact/contact';
import { Component } from '@angular/core';
import { NavController, ToastController } from 'ionic-angular';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  contacts: Observable<any>;

  constructor(public navCtrl: NavController, private provider: ContactProvider,
    private toast: ToastController) {

    this.contacts = this.provider.getAll();
  }

  newContact() {
    this.navCtrl.push('ContactEditPage');
  }

  editContact(contact: any) {
    // Maneira 1
    this.navCtrl.push('ContactEditPage', { contact: contact });

    // Maneira 2
    // this.navCtrl.push('ContactEditPage', { key: contact.key });
  }

  removeContact(key: string) {
    if (key) {
      this.provider.remove(key)
        .then(() => {
          this.toast.create({ message: 'Contato removido sucesso.', duration: 3000 }).present();
        })
        .catch(() => {
          this.toast.create({ message: 'Erro ao remover o contato.', duration: 3000 }).present();
        });
    }
  }
}

 

Arquivo home.html

<ion-header>
  <ion-navbar color="primary">
    <ion-title>
      Contatos
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>

  <ion-list>
    <ion-item-sliding *ngFor="let contact of contacts | async">
      <ion-item>
        <h1>{{ contact.name }}</h1>
        <p>{{ contact.tel }}</p>
      </ion-item>
      <ion-item-options side="left">
        <button ion-button color="secondary" (click)="editContact(contact)">
          <ion-icon name="create"></ion-icon>
        </button>
        <button ion-button color="danger" (click)="removeContact(contact.key)">
          <ion-icon name="trash"></ion-icon>
        </button>
      </ion-item-options>
    </ion-item-sliding>
  </ion-list>

  <ion-fab bottom right>
    <button ion-fab color="primary" (click)="newContact()">
      <ion-icon name="add"></ion-icon>
    </button>
  </ion-fab>
</ion-content>

 

Passo 5: Criar a pagina para inclusão/alteração de contatos

Arquivo contact-edit.ts

import { ContactProvider } from './../../providers/contact/contact';
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, ToastController } from 'ionic-angular';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@IonicPage()
@Component({
  selector: 'page-contact-edit',
  templateUrl: 'contact-edit.html',
})
export class ContactEditPage {
  title: string;
  form: FormGroup;
  contact: any;

  constructor(
    public navCtrl: NavController, public navParams: NavParams,
    private formBuilder: FormBuilder, private provider: ContactProvider,
    private toast: ToastController) {

    // maneira 1
    this.contact = this.navParams.data.contact || { };
    this.createForm();

    // // maneira 2
    // this.contact = { };
    // this.createForm();

    // if (this.navParams.data.key) {
    //   const subscribe = this.provider.get(this.navParams.data.key).subscribe((c: any) => {
    //     subscribe.unsubscribe();

    //     this.contact = c;
    //     this.createForm();
    //   })
    // }

    this.setupPageTitle();
  }

  private setupPageTitle() {
    this.title = this.navParams.data.contact ? 'Alterando contato' : 'Novo contato';
  }

  createForm() {
    this.form = this.formBuilder.group({
      key: [this.contact.key],
      name: [this.contact.name, Validators.required],
      tel: [this.contact.tel, Validators.required],
    });
  }

  onSubmit() {
    if (this.form.valid) {
      this.provider.save(this.form.value)
        .then(() => {
          this.toast.create({ message: 'Contato salvo com sucesso.', duration: 3000 }).present();
          this.navCtrl.pop();
        })
        .catch((e) => {
          this.toast.create({ message: 'Erro ao salvar o contato.', duration: 3000 }).present();
          console.error(e);
        })
    }
  }
}

 

Arquivo contact-edit.html

<ion-header>
  <ion-navbar color="primary">
    <ion-title>{{ title }}</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <form [formGroup]="form">
    <ion-item>
      <ion-label stacked>Nome</ion-label>
      <ion-input type="text" formControlName="name"></ion-input>
    </ion-item>
    <ion-item *ngIf="!form.controls.name.valid && (form.controls.name.dirty || form.controls.name.touched)" color="danger">
      <div [hidden]="!form.controls.name.errors.required">
        O campo é obrigatório
      </div>
    </ion-item>

    <ion-item>
      <ion-label stacked>Telefone</ion-label>
      <ion-input type="tel" formControlName="tel"></ion-input>
    </ion-item>
    <ion-item *ngIf="!form.controls.tel.valid && (form.controls.tel.dirty || form.controls.tel.touched)" color="danger">
      <div [hidden]="!form.controls.tel.errors.required">
        O campo é obrigatório
      </div>
    </ion-item>

    <div padding>
      <button ion-button block type="submit" [disabled]="!form.valid" (click)="onSubmit()">Salvar</button>
    </div>
  </form>
</ion-content>

 

Clique no botão abaixo para ver o código fonte gerado nessa aula

 

[button style=”btn-primary btn-lg” type=”link” target=”true” title=”Código fonte gerado na aula” link=”https://github.com/fabricadecodigo/ionicfirebasecrud” linkrel=””]

 

Quer aprender mais?

Clique no botão abaixo para aprender a criar uma aplicação de delivery com Ionic, Angular e Firebase.

Quer ver como ficou a aplicação? Clicando no botão abaixo, você vai poder ver um video onde eu mostro uma demonstração da aplicação criada e tudo o que você vai aprender no curso.

[button style=”btn-danger btn-lg” type=”link” target=”true” title=”Quero saber mais” link=”https://www.fabricadecodigo.com/ionic-e-firebase/oferta/?utm_source=site&utm_medium=botao-post&utm_campaign=cursoionicfirebase” linkrel=””]

 

Referências

 

Gostou desse artigo? Aproveite e curta e compartilhe para que mais pessoas possam também visualiza-lo!

Ainda ficou alguma dúvida ou tem alguma sugestão? Deixa aí nos comentários!