Tutorial

Using Cloud Firestore in Angular With AngularFire

Published on October 4, 2017
author

Alligator.io

Using Cloud Firestore in Angular With AngularFire

Cloud Firestore was just announced as a new database to fill-in the gap where the Firebase realtime database may not be the best tool. Cloud Firestore is a NoSQL, document-based database. At the root of the database are collections (e.g.: todos, users, files) and collections can only contain documents. Documents contain key-value pairs and can contain collections of their own, called subcollections. This therefore makes it easier to build apps that have more complex hierarchical needs compared with the flat JSON tree offered with the traditional Firebase realtime database.

Here’s we’ll cover the very basics of using interacting with Cloud Firestore in an Angular 2+ project. You’ll need to have a Firebase account and to enable the new database.

Setup

First, install the needed Firebase packages (firebase & angularfire2) into your Angular project:

$ yarn add firebase angularfire2

# or, using npm:
$ npm install firebase angularfire2

And then add both the AngularFireModule and AngularFirestoreModule to your app module:

app.module.tsc
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AngularFireModule } from 'angularfire2';
import { AngularFirestoreModule } from 'angularfire2/firestore';
import { environment } from '../environments/environment';
import { AppComponent } from './app.component';

Note that we call the enablePersistence method on the AngularFirestoreModule to automatically enable local caching on Chrome, Safari and Firefox, which will allow the app to stay available while offline.

And with this, your Firebase app configuration would be inside the enviroment.ts file like this:

/enviroments/enviroment.ts
export const environment = {
  production: false,
  firebase: {
    apiKey: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    authDomain: 'your-project-id.firebaseapp.com',
    databaseURL: 'https://your-project-id.firebaseio.com',
    projectId: 'your-project-id',
    storageBucket: 'your-project-id.appspot.com',
    messagingSenderId: 'XXXXXXXXXXXX'
  }
};

Basic Usage

Now that our app is configured with Firebase, we can start playing around with the database. We’ll demonstrate a few of the CRUD operations around the idea of a simple todo app that contains a todos collection and documents within that collection that contain a description and a completed field.

First you’ll want to inject the AngularFirestore injectable into your component:

import { Component } from '@angular/core';
import { AngularFirestore } from 'angularfire2/firestore';

@Component({ ... })
export class AppComponent {
  constructor(private afs: AngularFirestore) {
    // ...
  }
}

To get access to a collection, you create a reference to it with something like this:

this.todoCollectionRef = this.afs.collection('todos'); // a ref to the todos collection

Creating a reference to a collection doesn’t do any network call and it’s safe to reference collections that don’t exist, as the collection will be automatically created if needed. A collection without any document will also be automatically removed.

You can then listen for changes on the collection’s documents by calling valueChanges() on the collection reference:

this.todo$ = this.todoCollectionRef.valueChanges();

The valueChanges method returns an observable of the documents in the collection. There’s also a snapshotChanges, method that also returns the id as well as metadata about our documents. Read-on for an example using snapshotChanges instead.


Here’s therefore our starting todo app, which will get the documents inside the todos collection from the database:

app.component.ts
import { Component } from '@angular/core';
import {
  AngularFirestore,
  AngularFirestoreCollection
} from 'angularfire2/firestore';

import { Observable } from 'rxjs/Observable';
export interface Todo {
  description: string;
  completed: boolean;
}
@Component({ ... })
export class AppComponent {
  todoCollectionRef: AngularFirestoreCollection<Todo>;
  todo$: Observable<Todo[]>;

And we can display our todo items in the template with something as simple as this:

app.component.html
<ul>
  <li *ngFor="let todo of todo$ | async"
      [class.completed]="todo.completed">
    {{ todo.description }}
  </li>
</ul>

Adding items

To add a new document in a collection, simply call add on the collection reference:

addTodo(todoDesc: string) {
  if (todoDesc && todoDesc.trim().length) {
    this.todoCollectionRef.add({ description: todoDesc, completed: false });
  }
}

Thanks to our todo collection reference being typed against our Todo interface, the TypeScript compiler will know the shape of the data that should be passed using the add method.

Updating and Deleting Items

To update or delete a document in the collection, we’ll also need the document’s id, which is not returned with the valueChanges method. We’ll change our implementation a bit to use the snapshotChanges method instead and also include the id for each todo document:

app.component.ts
import { Component } from '@angular/core';
import {
  AngularFirestore,
  AngularFirestoreCollection
} from 'angularfire2/firestore';

import { Observable } from 'rxjs/Observable';
export interface Todo {
  id?: string;
  description: string;
  completed: boolean;
}
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  todoCollectionRef: AngularFirestoreCollection<Todo>;
  todo$: Observable<Todo[]>;

We map over the observable returned by snapshotChanges to extract the document’s id along with its data.

Actions returned by snapshotChanges are of type DocumentChangeAction and contain a type and a payload. The type is either added, modified or removed and the payload contains the document’s id, metadata and data.

With this in place, everything still works the same, and we can now easily implement updating and deleting todo documents and have the changes reflected immediately to our template:

app.component.ts (partial)
updateTodo(todo: Todo) {
  this.todoCollectionRef.doc(todo.id).update({ completed: !todo.completed });
}

deleteTodo(todo: Todo) {
  this.todoCollectionRef.doc(todo.id).delete();
}

Learning more

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Alligator.io

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
2 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Could you please continue the implementation with the todo$ Observable in the CRUD? I can’t see a Read and Query methods implemented here. :)

You rock!! This post was helpful! Just one thing you might need to update, now use use @angular/fire instead of the deprecated ones. ;)

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.