Como criar um aplicativo com Firebase Realtime database e Angular

Nesse artigo você vai aprender como criar seu primeiro aplicativo com
o armazenamento de banco de dados com Firebase e Angular.
Para saber mais sobre o Firebase acesse o site clicando aqui.

 

O que é o Firebase Realtime Database?

O Firebase Realtime Database é um banco de dados online. Os dados são armazenados em formato JSON e sincronizados em tempo real com todos os clientes conectados independente da plataforma (Android, iOS, Web).

 

arvore do banco de dados - angular 2 e firebase

 

Realtime Database fornece uma linguagem de regras declarativas que permite que você defina como os dados devem ser estruturados, como devem ser indexados e quando podem ser lidos e gravados. Por padrão, o acesso de leitura e gravação ao seu banco de dados é restrito, exceto para usuários autenticados, portanto, você deve configurar as regras antes de começar

O Firebase Realtime Database permite você a criar um conjunto de regras para definir quando os dados podem ser lidos e gravados e também como indexar os dados para facilitar nas consultas.

Por padrão, as regras permitem que qualquer usuário identificado pode ler e gravar dados. Para saber mais sobre como criar regras e indexar os dados você pode clicar aqui. Na aplicação que será construída de exemplo vamos utilizar as regras e o index abaixo:

{
  "rules": {
        ".read": "true",
        ".write": "true",
      "tasks": {
        ".indexOn": ["done"]
      }
  }
}

 

regras do banco de dados - angular 2 e firebase

 

Criando uma aplicação de exemplo

Seguindo os passos abaixo você vai conseguir criar seu primeiro aplicativo com o Firebase Realtime Database. Como exemplo será criado um aplicativo de cadastro de tarefas.

 

demo - angular 2 e firebase

 

O que você vai aprender?

  • Criar uma aplicação com Angular 2 do zero.
  • Configurar a apliação para integrar com o Firebase.
  • Incluir, alterar, excluir e consultar dados no Firebase Realtime Database

 

Pré-requisitos:

 

1 – Criando um projeto no Firebase

Criar um projeto no Firebase é muito simples. Seguindo os passos abaixo você irá criar um projeto em poucos minutos.

 

1 – Na pagina principal do Firebase, apos efetuar o login com sua conta do Google, clique em “Ir para o console“.

 

2 – Agora clique no botão “Criar novo projeto”

 

3 – No modal que se abrir, informe o “nome do projeto”, a “região” e clique em “criar projeto”.

 

criando projeto no firebase - angular 2 e firebase

 

4 – Quando o processo terminar, clique no nome do projeto para ser redirecionado para o console do projeto.

 

2 – Criando um projeto com Angular

Criar um projeto do zero com Angular é muito simples basta seguir o passo a passo abaixo:

 

1 – Baixe o Angular 2 QuickStart direto do repositório do Angular no GitHub clicando aqui. Ou use os comandos abaixo:

git clone https://github.com/angular/quickstart.git nomedoseuprojeto
cd nomedoseuprojeto
npm install

 

2 – Delete os arquivos que não são necessários (opcional):

for /f %i in (non-essential-files.txt) do del %i /F /S /Q
rd .git /s /q
rd e2e /s /q

 

3 – Para ver o projeto em funcionamento no navegador utilize o comando abaixo:

npm start

 

3 – Adicionando Firebase ao projeto

Para manipular o Firebase vamos utilizar a biblioteca oficial do Angular que é a AngularFire2.

Vamos também utilizar o npm para instalar as dependências com o Firebase e o AngularFire2.

Na publicação desse artigo as versões estáveis das bibliotecas do Firebase e AngularFire2 são “3.4.0” e “2.0.0-beta.8” respectivamente.

 

1 – Abra o aquivo package.json e adicione as linhas abaixo em “dependencies”.

"firebase": "3.4.0",
"angularfire2": "2.0.0-beta.8"

 

2 – Abra o arquivo src/systemjs.config.js

Em map adicione as linhas abaixo:

'angularfire2': 'npm:angularfire2/bundles',
'firebase': 'npm:firebase'

Em packages adicione as linhas abaixo:

angularfire2: {
        main: 'angularfire2.umd.js'
},
firebase: {
        main: 'firebase.js'
}

 

3 – Navegue até a pasta do projeto e execute o comando abaixo para instalar as dependências na versões especificadas:

npm install

 

4 – Abra o arquivo src/app/app.module.ts e adicione o provider e as configurações do Firebase:

Você pode pegar suas configurações do Firebase na pagina inicial do projeto clicando no botão “Adicionar o Firebase ao seu aplicativo da Web”.

 

onde pegar as configuracoes do firebase - angular 2 e firebase

Arquivo src/app/app.module.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';
import { AngularFireModule } from 'angularfire2';

export const firebaseConfig = {
  apiKey: '[SUA-APIKEY]',
  authDomain: '[SEU-AUTH-DOMAIN]',
  databaseURL: '[SUA-DATABASE-URL]',
  storageBucket: '[SEU-STORAGE-BUCKET]',
  messagingSenderId: '[SEU-MESSAGING-SENDER-ID]'
};

@NgModule({
  imports:      [
    BrowserModule,
    AngularFireModule.initializeApp(firebaseConfig)
  ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

 

4 – Criando o componente para criar tarefas

1 – Criar uma classe de nome task.model.ts no caminho src/app/todo/ para colocar quais serão as propriedades de uma tarefa. Para uma tarefa precisamos de um titulo, descrição, uma flag para informar se está ou não concluída e a propriedade $key que será o identificador do registro no Firebase.

Arquivo src/app/todo/task.model.ts

export class Task {
  done: boolean;
  title: string;
  description: string;
  $key: string;
}

 

2 – Agora vamos criar o serviço que vai fazer as operações de incluir, alterar, excluir e consultar os registros no Firebase.

Para isso vamos criar um arquivo de nome task.service.ts no caminho src/app/todo/

import { Injectable } from '@angular/core';
import { Task } from './task.model';
import { AngularFire, FirebaseListObservable } from 'angularfire2';

@Injectable()
export class TaskService {
  angularfire: AngularFire;
  items: FirebaseListObservable<any>;

  constructor(af: AngularFire) {
    this.angularfire = af;
  }

  getAll() {
    // Buscando todos os itens no no "/task"
    this.items = this.angularfire.database.list('/tasks');
    return this.items;
  }

  getAllCompleted() {
    // Buscando todos os itens que estão completos
    this.items = this.angularfire.database.list('/tasks',  {
      query: {
        orderByChild: 'done', // filtrando pelo campo "done"
        equalTo: true // e que tanha o valor true
      }
    });
    return this.items;
  }

  getAllOpened() {
    // Buscando todos os itens que estão em aberto
    this.items = this.angularfire.database.list('/tasks',  {
      query: {
        orderByChild: 'done', // filtrando pelo campo "done"
        equalTo: false // e que tanha o valor false
      }
    });
    return this.items;
  }

  add(task: Task) {
    // Adicionando uma nova tarefa.
    // Toda nova tarefa é gravada como em aberto por padrão.
    task.done = false;

    // Adicionando o item na lista de itens. 
    // Como essa lista é carregada antes, automaticamente o angularfire2
    // identifica a mudança na lista e inclui o item novo.
    this.items.push(task);
  }

  update(task: Task) {
    // Atualizando o item na lista.
    // Para isso passamos por parametro qual é o id do item no Firebase
    // e quais são os novos valores.
    this.items.update(task.$key, task);
  }

  save(task: Task) {
    // Metodo criado para facilitar a inclusão/alteração e um item.
    // Verifico se o item tem o Id para saber se é uma inclusão ou alteração.
    if (task.$key == null) {
      this.add(task);
    } else {
      this.update(task);
    }
  }

  remove(task: Task) {
    // Removendo um item da lista
    this.items.remove(task.$key);
  }

  toggleDone(task: Task) {
    // Marcando uma tarefa como concluída ou em aberto.
    task.done = !task.done;
    this.update(task);
  }
}

 

3 – Agora vamos criar o componente que ira exibir o formulário para inclusão/alteração e os itens na tela. Para isso vamos criar o arquivo task.component.ts no caminho src/app/todo/

import { Component, OnInit } from '@angular/core';
import { Task } from './task.model';
import { TaskService } from './task.service';
import { FirebaseListObservable } from 'angularfire2';

@Component({
  selector: 'todo-task',
  templateUrl: 'app/todo/task.component.html'
})
export class TaskComponent implements OnInit {
  tasks: FirebaseListObservable<any>;
  task: Task;

  constructor(private taskService: TaskService) {
    this.task = new Task();
  }

  ngOnInit() {
    // Ao iniciar o componente, busco todos os items já existentes no Firebase.
    this.tasks = this.taskService.getAll();
  }

  saveTask() {
    // Se os campos do formulario foram preenchidos, adiciono a nova tarefa.
    if (this.task.title && this.task.description) {
      this.taskService.save(this.task);
      this.task = new Task();
    }
  }

  editTask(task: Task) {
    // Ao clicar 2x em um item da lista e vai para o formulário para ser editado.
    this.task = task;
  }

  remove(task: Task) {
    this.taskService.remove(task);
  }

  toggleDone(task: Task) {
    this.taskService.toggleDone(task);
  }

  filterTasks(filter: number) {
    // Filtrando os itens
    switch (filter) {
      case 1: // Todos
        this.tasks = this.taskService.getAll();
        break;
      case 2: // Todas tarefas em aberto
        this.tasks = this.taskService.getAllOpened();
        break;
      case 3: // Todas tarefas concluídas
        this.tasks = this.taskService.getAllCompleted();
        break;
    }
  }
}

 

4 – E agora o arquivo HTML que será o template do componente. Para isso vamos criar o arquivo task.component.html no caminho src/app/todo/

<h1 class="text-center">ToDo - Fábrica de Código</h1>

<div class="row">
    <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">

        <div class="panel panel-primary">
            <div class="panel-body">
                <form role="form" novalidate>
                    <div class="form-group">
                        <label for="title">Título</label>
                        <input [(ngModel)]="task.title" type="text" class="form-control" id="title" name="title" placeholder="O que você deseja fazer?" required />
                    </div>

                    <div class="form-group">
                        <label for="description">Descrição</label>
                        <input [(ngModel)]="task.description" type="text" class="form-control" id="description" name="description" placeholder="Uma pequena descrição" required />
                    </div>

                    <button type="submit" class="btn btn-primary" (click)="saveTask()">Salvar</button>                    
                </form>
            </div>
        </div>
    </div>
</div>

<div class="row">
    <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
        <div class="panel panel-primary">
            <div class="panel-heading">
                <h3 class="panel-title">Tarefas</h3>
            </div>
            <div class="panel-body">
                <div class="bs-callout" *ngFor="let task of tasks | async" [ngClass]="{ 'bs-callout-primary': !task.done }">
                    <div class="row">

                        <div class="col-xs-1 col-sm-1 col-md-1 col-lg-1">
                            <input type="checkbox" [checked]="task.done" (click)="toggleDone(task)" />
                        </div>

                        <div class="col-xs-10 col-sm-10 col-md-10 col-lg-10" (dblclick)="editTask(task)">
                            <h4 [ngClass]="{ 'item-done': task.done }">{{task.title}}</h4>
                            <div [ngClass]="{ 'item-done': task.done }">{{task.description}}</div>
                            <div>{{ task.$value }}</div>
                        </div>

                        <div class="col-xs-1 col-sm-1 col-md-1 col-lg-1 remove">
                            <a (click)="remove(task)">
                                <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
                            </a>
                        </div>
                    </div>
                </div>
            </div>            
            <div class="panel-footer">
                <label class="radio-inline">
                    <input (click)="filterTasks(1)" type="radio" name="statusTask" id="todos" value="1" checked > Todas
                </label>
                <label class="radio-inline">
                    <input (click)="filterTasks(2)" type="radio" name="statusTask" id="ativos" value="2"> Ativas
                </label>
                <label class="radio-inline">
                    <input (click)="filterTasks(3)" type="radio" name="statusTask" id="completas" value="2"> Completas
                </label>
            </div>
        </div>
    </div>
</div>

Atenção para listar os itens é necessário usar o Pipe async do angular para garantir que sempre vamos listar os valores mais atuais do Firebase.

 

5 – Agora é necessário modificar o arquivo src/app/app.component.ts e adicionar o serviço TaskService, que foi criado acima, como um provider.

import { Component } from '@angular/core';
import { TaskService } from './todo/task.service';

@Component({
  selector: 'todo-app',
  template: `<todo-task></todo-task>`,
  providers: [ TaskService ]
})
export class AppComponent { }

 

6 – E por fim precisamos editar o arquivo src/app/app.module.ts novamente e incluir as referencias para o FormsModule do angular e o componente TaskComponent criado acima.

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';
import { AngularFireModule } from 'angularfire2';
import { FormsModule }   from '@angular/forms';
import { TaskComponent }  from './todo/task.component';


export const firebaseConfig = {
  apiKey: 'AIzaSyCz7kugPPNI24kcVjjNTO4HiGpqKDvn8J0',
  authDomain: 'todofabricadecodigo-c6949.firebaseapp.com',
  databaseURL: 'https://todofabricadecodigo-c6949.firebaseio.com',
  storageBucket: 'todofabricadecodigo-c6949.appspot.com',
  messagingSenderId: '902107944829'
};

@NgModule({
  imports:      [
    BrowserModule,
    FormsModule,
    AngularFireModule.initializeApp(firebaseConfig)
  ],
  declarations: [ AppComponent, TaskComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

 

Conclusão

É muito simples fazer uma integração entre o Angular e o Firebase e apesar o AngularFire2 ser uma biblioteca ainda em fase beta, ela fornesse bastante recurso para que você consiga trabalhar com o Firebase.

 

Referencias:

 

Eu espero que esse tutorial tenha sido útil para você. Qualquer dúvida
deixe seu comentário abaixo.