Angular
3/20/2017

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 referências 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: "REPLACE",
    authDomain: "REPLACE",
    databaseURL: "REPLACE",
    storageBucket: "REPLACE",
    messagingSenderId: "REPLACE",
};

@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.

referências:

Eu espero que esse tutorial tenha sido útil para você.