This article will guide you through the entire setup of a simple todo app that can be deployed on mobile devices or served as a PWA. The main features of the app will be realtime data sync across client apps and offline support. We’ll use Ionic to build the app and Firebase’s new database engine: Cloud Firestore.
TL;DR
There’s a repository of a complete app available at https://github.com/front/frontmag-todo-app. You can also check the demo at https://frontmag-todos.firebaseapp.com/
Just be sure to check the bonus at the end of this article.
Let’s do it!
Go to Firebase site, sign up if you already haven’t and create a new project. Then go to Database and on Cloud Firestore Beta card click “Get started”

And that’s all you have to do in the Firebase console.
Install Ionic if you already haven’t
npm install -g ionic
You’re ready to create your app!
ionic start todo-app blank
Using Ionic CLI you can quickly create a service provider the will handle communication with Firebase (or the AngularFire2 module to be more precise)
ionic g provider Todos
To handle Firebase and Cloud Firestore flow, let’s use AngularFire2 and Firebase modules
npm install angularfire2 firebase
Create a environment settings file at /src/environment.ts
export const firebaseConfig = {
apiKey: 'AIzaSyACjzK5Edn9mwTe3pY35oy9TWWLZjhykt4',
authDomain: 'frontmag-todos.firebaseapp.com',
databaseURL: 'https://frontmag-todos.firebaseio.com',
projectId: 'frontmag-todos',
storageBucket: 'frontmag-todos.appspot.com',
messagingSenderId: '478702080463'
};
You can use the above settings but probably you would like to replace it with your own Firebase project settings.
Add AngularFire2 and Firebase imports at /src/app.module.ts and also the settings
import { AngularFireModule } from 'angularfire2';
import { AngularFirestoreModule } from 'angularfire2/firestore';
import { firebaseConfig } from '../environment';
imports: [
BrowserModule,
AngularFireModule.initializeApp(firebaseConfig),
AngularFirestoreModule.enablePersistence(),
IonicModule.forRoot(MyApp)
],
Check the complete source code at https://github.com/front/frontmag-todo-app/blob/master/src/app/app.module.ts
Notice the AngularFirestoreModule.enablePersistence(), this is what triggers the offline data features of our app. Easy, huh? More information at https://firebase.google.com/docs/firestore/manage-data/enable-offline
You’re ready to add some methods to our Todos service provider at /src/todos/todos.ts
import { Injectable } from '@angular/core';
import { AngularFirestore } from 'angularfire2/firestore';
import firebase from 'firebase';
/*
Generated class for the TodosProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
@Injectable()
export class TodosProvider {
constructor(public db: AngularFirestore) {
console.log('Hello TodosProvider Provider');
}
list() {
return this.db.collection('/todos', ref => ref.orderBy('complete').orderBy('text')).valueChanges();
}
add(text) {
const id = this.db.createId();
return this.db.collection('todos').doc(id).set({
id: id,
text: text,
complete: false,
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
updatedAt: firebase.firestore.FieldValue.serverTimestamp()
});
}
complete(todo) {
return this.db.collection('todos').doc(todo.id).update({
complete: todo.complete,
updatedAt: firebase.firestore.FieldValue.serverTimestamp()
});
}
delete(todo) {
return this.db.collection('todos').doc(todo.id).delete();
}
}
Now that we have all the backend stuff in place, let’s move to the frontend and build the UI to manage our todos.
At /src/pages/home/home.ts:
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { TodosProvider } from '../../providers/todos/todos';
import { Observable } from 'rxjs/Observable';
@Component({
selector: 'page-home',
templateUrl: 'home.html',
providers: [TodosProvider]
})
export class HomePage {
public todos: Observable<any[]>;
public todo: String = '';
constructor(public navCtrl: NavController, public todosProvider: TodosProvider) {
this.todos = this.todosProvider.list();
}
addTodo() {
if (!this.todo) {
return;
}
this.todosProvider.add(this.todo);
this.todo = '';
}
completeTodo(todo) {
this.todosProvider.complete(todo);
}
deleteTodo(todo) {
this.todosProvider.delete(todo);
}
}
At /src/pages/home/home.html
<ion-header>
<ion-navbar>
<ion-title>
Todos
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-list>
<ion-item>
<ion-label>To do <ion-icon name="arrow-round-forward"></ion-icon></ion-label>
<ion-input type="text" [(ngModel)]="todo"></ion-input>
<button (click)="addTodo($event)" ion-button outline item-end>Add</button>
</ion-item>
</ion-list>
<ion-list>
<ion-item-sliding *ngFor="let todo of todos | async">
<ion-item ngClass="{{todo.complete?'done':''}}">
<ion-checkbox [(ngModel)]="todo.complete" (ionChange)="completeTodo(todo)"></ion-checkbox>
<ion-label>{{ todo.text }}</ion-label>
</ion-item>
<ion-item-options side="right">
<button ion-button icon-only (click)="deleteTodo(todo)">
<ion-icon name="remove-circle"></ion-icon>
</button>
</ion-item-options>
</ion-item-sliding>
</ion-list>
<p ng-if="todos" text-center>Slide an item to left to show more options</p>
</ion-content>
And finally some style for the completed todos, at /scr/pages/home/home.scss
page-home {
.item {
&.done {
text-decoration: line-through;
}
}
}
And that’s it! You’ve got yourself a simple todo app ready to run. To preview it just
ionic serve
Hmm … you’re running with your own Firebase project settings and it doesn’t work, does it?

That’s because Cloud Firestore needs to create an index in order to be able to sort by complete status and text fields. Just follow the provided link to create the index or add it manually on your Firebase console.
PWA?
The app isn’t quite a PWA yet, you need to enable the service worker by un-commenting the following block at /src/index.html
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js')
.then(() => console.log('service worker installed'))
.catch(err => console.error('Error', err));
}
</script>
Congratulations! You have built a real-time data with offline support app in a few simple steps. You can use Firebase to host your PWA in, also, a few simple steps. Check it out here. Or just use Ionic to deploy to iOS, Android or Windows devices.
Bonus – Serverless Cron
For our demo project database at Firebase, the completed todos older than a week get deleted automatically. And we’re doing this without any server. Well, at least, any server maintained by us 😉
Cloud functions, do your “clouding”
Firebase provides Cloud Functions, a service that allows you to automatically run backend code through triggers or requests.
In our case, we use a request function triggered by EasyCron.
Check the /functions folder on the repository.
Leave your reply