How to CRUD in Angular + Firebase Firestore

Angular - The Ultimate Walkthrough Learning Guide
What do you need to learn to become an Angular Master? The journey can feel overwhelming. The YouTube series can feel like it’s only covering the basics. That’s why I’ve created this Walkthrough Learning Guide to help you get started on your Angular journey. From zero to pro, these articles

CRUD — Create, Read, Update, Delete — the four holy grail of database actions. They are the only things you’ll ever need to do anything significant with your database. Sure, you can increase the complexity of the queries but at the end of the day, it all boils down the these four actions.

Firebase is a Google owned cloud based system that comes complete with API hooks, file storage space, auth system and hosting capabilities. It’s a much underrated system that should be utilized more for prototyping and rapid application development.

If you want to boot up a progressive web app but don’t have the backend experience of setting up servers, creating APIs and dealing with databases, then Firebase makes a fantastic option for front end developers who may feel isolated and bogged down by the massive hill of information they have to process to even get their app up and running.

Or if you’re just short on time, Firebase can cut your development hours almost in half so you can focus on user experience and implementing those UI flows. It’s also flexible enough to migrate out your front end application and use a different database if needed.

Here’s a quick guide on how to implement CRUD actions with Angular and Firebase.

What we’ll be making

It’s a bare bones coffee ordering app where you can add orders (create), list orders from the database (read), mark order as completed (update) and remove an order (delete).

The purpose of this tutorial is to help you get started with Firebase Firestore and see how easy it is to connect to and get started on the Google owned service. This is not an advert for Google (I get no kickbacks from them for this) but merely an illustration of how Angular plays with the database.

The app we’re going to make is not perfect. There are things missing like data validation and a million possible features that I can also add. But that’s not the point. The point is to set up in Angular as quickly as possible and get it working with a live database.

So, enough of the intro — here’s the code walk through.

The initial setup

Set up your Angular app via the Angular CLI. If you don’t already have Angular CLI, you can find out more about it here.

In short, simply run these commands in your terminal in the directory where you want your Angular app to sit. Here are the commands and what they do.

npm install -g @angular/cli

Installs Angular CLI on your terminal if you don’t already have it.

ng new name-of-app-here

This will create a new Angular project using the latest version of Angular available.

cd name-of-app-here

When you create a new project via Angular CLI, it will create a new project folder for you. cd will take you into that folder via the terminal.

ng serve

This is will start and run your Angular project.

Setting up Angular

The structure

We’re going to create 3 new parts in total for this Angular app — orders, order-list and shared/ordersService. The first two are components that will contain the interface for the app and the shared/orders service which will keep all the Firebase API calls together.

To create the necessary files, run the following commands:

ng g c orders

g stands for generate and c stands for component. The last part of the command is the name of your file, which for the case above is called orders. You can also use ng generate component orders to achieve the same effect.

Create another component for order-list using the following command.

ng g c order-list

And finally, for the service, use s instead of c like below:

ng g s shared/orders

This will create an orders.service.ts file in a folder named shared. Be sure to add orders.service.ts into app.module.ts because this is not done for you automatically like the components. You can do this via import and adding it to the providers list like so:

import { OrdersService } from "./shared/orders.service";
...
providers: [OrdersService]
...

The CSS

For this tutorial, we’ll be using Materialize CSS to make our final application look better than the default css. It’s not necessary and you can use whatever CSS framework or your own custom CSS if you want. You can check out the details of Materialize CSS here.

We’re also going to use Googles’s material icons as buttons to mark the coffee order as completed or delete the order.

One way to implement this is to have the code below right above the </head> tag in your index.html file located in the src folder.

<!-- Compiled and minified Materialize CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">

<!-- Compiled and minified Materialize JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<!-- Google Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"  rel="stylesheet" />

The initial Angular view code

In app.component.html, delete all the starter code. We’ll be using our own content for this.

We’ll hook into the component we’ve just created and display them on the screen by using the selectors app-orders and app-order-list. To do this, we write the code below:

<div class="container">
    <div class="row">
        <app-orders class="col s6"></app-orders>
        <app-order-list class="col s6"></app-order-list>
    </div>
</div>

The container, row, col and s6 classes are part of Materialize CSS grid system. All classes that you will see in the rest of this tutorial is from Materialize CSS, unless mentioned otherwise.

Setting up the form

In order to set up forms, import ReactiveFormsModule in app.module.ts and remember to import it in the imports array.

import { ReactiveFormsModule } from "@angular/forms";

Inside orders.service.ts import FormControl and FormGroup from @angular/formsand create a new form outside the constructor where you can set the properties of the form as below:

import { FormControl, FormGroup } from "@angular/forms";
...
...
export class OrdersService {
    constructor() {}
    form = new FormGroup({        
        customerName: new FormControl(''),
        orderNumber: new FormControl(''),
        coffeeOrder: new FormControl(''), 
        completed: new FormControl(false)
    })
}

We’ll use these values to store in Firebase a little later in this tutorial.

Using the form inside a component

import the OrdersService class into your component so you can use the object inside your component and then create an object of the class inside the constructor.

import { OrdersService } from "../shared/orders.service";
...
constructor(private ordersService:OrdersService){}

Inside your orders.component.html use the formGroup directive to reference the form object created in OrdersService. Each formControlName references the names we used in the formGroup created inside the OrdersService class. This will allow the associated controller to use the variables typed into the form. See code below:

<form [formGroup]="this.ordersService.form">
    <input placeholder="Order Number" 
           formControlName="orderNumber" 
           type="text" 
           class="input-field col s12">
    <input placeholder="Customer Name" 
           formControlName="customerName" 
           type="text" 
           class="input-field col s12">
</form>

In the orders.component.ts, we’re going to set up an array off coffee for looping through on our orders.component.html. In theory, you could also set this up inside your Firestore database, do a call to the collection and then use it. But for purposes of length, we’re going to set it up as a local array. Inside your OrdersComponent class, set up the following array:

coffees = ["Americano", "Flat White", "Cappuccino", "Latte", "Espresso", "Machiato", "Mocha", "Hot Chocolate", "Tea"];

In your orders.component.html and inside your <form> tags, loop through it using *ngFor with an (click) action handler to add new coffees to your order. We’re going to display the order list right below with the ability to remove individual coffee as following:

<button class="waves-effect waves-light btn col s4" 
        *ngFor="let coffee of coffees" 
        (click)="addCoffee(coffee)">
{{coffee}}
</button>
<ul class="collection">
    <li *ngFor="let coffee of coffeeOrder">
        <span class="col s11"> {{ coffee }} </span>
        <a class="col s1" (click)="removeCoffee(coffee)">x</a>
    </li>
</ul>

Inside orders.component you create an empty array to house the coffee order, use the function addCoffee() to add new coffees, and removeCoffee() to remove a beverage from your order list.

coffeeOrder = [];
addCoffee = coffee => this.coffeeOrder.push(coffee);
removeCoffee = coffee => {
    let index = this.coffeeOrder.indexOf(coffee);
    if (index > -1) this.coffeeOrder.splice(index, 1);
};

Handling form submission

Add a Submit Order input inside and at the bottom of the <form> tags and add the onSubmit() to a click handler like below:

<form [formGroup]="this.ordersService.form" (ngSubmit)="onSubmit()"> ...
  <button 
       class="waves-effect waves-light btn col s12" 
       (click)="onSubmit()">
  Submit
  </button>
</form>

Create an empty onSubmit function in your orders.component for the interim. We will be adding event handling to it soon. At this point, your form should be ready to go for hooking up to your Firebase database.

Setting up the listing component

Now we just need a space to display our coffee orders from the database. For now, we’re just going to set up the scaffold html.

Navigate to your order-list.component.html and create a table with 3 headings and 5 data cells. The first 3 data cells will hold the values pulled from the database and final 2 will hold extra functionality that will allow you to mark the order as complete or delete the order.

Setting up Firebase

Go to your Firebase console and add a new project.

Add a project name, accept the terms and conditions and click on create project.

Give your project a name and accept the controller-controller terms in order to create a project.

When your Firebase project has been set up, you will see something like this.

Create a database by selecting Database on the side panel (located under Develop) and then click on Create Database under the Cloud Firestore banner.

Select start in test mode for security rules. You can modify it later.

emember to keep your credentials on your local machine only for security purposes.

You will get an empty Firestore database like this.

Connecting Firebase Firestore to Angular

Installing the connectors

To connect your Angular app to Firebase, you’re going to need install firebase and @angular/fire packages. This will give you access to AngularFireModule and AngularFirestoreModule. Use the following command in your terminal to install them.

npm i --save firebase @angular/fire

Implementing the connectors

Go back to your Firebase web console and grab the config details to use in your Angular app. This is located on your Project Overview page. It looks something like this:

You’ll need to use your own credentials. The above config won’t work for you.