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
- Firebase Realtime Database: https://firebase.google.com/products/database/
- Firebase Realtime Database docs: https://firebase.google.com/docs/database/
- AngularFire2: https://github.com/angular/angularfire2/
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!