Offline Sync With AngularFire2

First Published: 26 July 2017
Updated on: 24 September 2018

NOTE: This post is out-dated, instead of using a 3rd party library you can use Cloud Firestore, the offline by default new database.

One of the most asked questions I get is always around how to get Firebase to work offline with Ionic apps, for when our users are on unstable connections.

I’ve always given the same answer, “I’m waiting for Firebase to add official support for their JS SDK so I can use it”. But let’s face it, it has been a long wait and still nothing.

Digging around a little and I found a really cool and easy to use library called AngularFire2 Offline from Adrian Carriger.

I’ve been playing with it for a few days, and I’ve found it very easy to use, to the point and the best thing is there’s not a lot of configuration or changes you’ll need to do to get it working.

With that intro let’s just jump into coding.

AngularFire2 Offline

The first thing you need to do to get this working is to install the library (assuming you already have an Ionic app created and are inside the app’s folder), just open the terminal and type:

npm install angularfire2-offline angularfire2 firebase

Once that’s installed, go into your app.module.ts file, import and initialize both AF2 and AF2 Offline:

import { AngularFireModule } from 'angularfire2';
import { AngularFireOfflineModule } from 'angularfire2-offline';
import { AngularFireDatabaseModule } from 'angularfire2/database';

export const firebaseConfig = {
  apiKey: "Your Firebase Credentials",
  authDomain: "Your Firebase Credentials",
  databaseURL: "Your Firebase Credentials",
  projectId: "Your Firebase Credentials",
  storageBucket: "Your Firebase Credentials",
  messagingSenderId: "Your Firebase Credentials"
};

@NgModule({
  declarations: [...],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFireDatabaseModule,
    AngularFireOfflineModule
  ],
  bootstrap: [IonicApp],
  entryComponents: [...],
  providers: [...]
})
export class AppModule {}

Notice how we’re adding the AngularFireOfflineModule to the input declaration.

Now that our app is initialized we can start playing with the library, let’s go into home.html and display a simple list of song names, the idea is that the list persist there even if we go offline and have a hard refresh.

<ion-header>
  <ion-navbar>
    <ion-title>
      Playlist
    </ion-title>
    <ion-buttons end>
      <button ion-button icon-only (click)="addSong()">
        <ion-icon name="add"></ion-icon>
      </button>
    </ion-buttons>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-list>
    <ion-item *ngFor="let item of items | async">
      {{ item.songName }}
    </ion-item>
  </ion-list>
</ion-content>

We’re displaying the list inside our <ion-content></ion-content> tags, and we’re adding a small button to the navigation bar to add new songs to our list.

We will create new songs offline, and they will sync to the database once we go online again.

Now let’s get all that functionality working, move to home.ts and import what we’ll need:

import { Component } from '@angular/core';
import { NavController, AlertController } from 'ionic-angular';

import {
  AfoListObservable,
  AngularFireOfflineDatabase
} from 'angularfire2-offline/database';

The cool thing about this offline library is that it works the same as AF2 does, so all the method names are the same.

So to get our HTML working and display the list all we need to do is create a list observable from the database

public items: AfoListObservable<any[]>;
constructor(afoDatabase: AngularFireOfflineDatabase,
  public alertCtrl: AlertController) {
  this.items = afoDatabase.list('/items');
}

We haven’t done anything different than what we’d do using regular AngularFire2, and already have offline persistence for our data, go ahead and store some data in your database, kill the internet and do a hard refresh, you’ll see all the data is still there.

Now if we want to add songs to the list, we use the regular .push() function for AngularFire2

addSong(): void {
  const prompt = this.alertCtrl.create({
    title: 'Add Song',
    message: "Add a new song to your playlist",
    inputs: [
      {
        name: 'songName',
        placeholder: 'Song Name'
      },
    ],
    buttons: [
      {
        text: 'Cancel',
        handler: data => {
          console.log('Cancel clicked');
        }
      },
      {
        text: 'Save',
        handler: data => {
          this.items.push({
            songName: data.songName
          });
        }
      }
    ]
  });
  prompt.present();
}

We’re just pushing the song with one property: songName. This is the exact same way you push objects to a list in AngularFire2, now go ahead and kill the internet and add a new song, you’ll see the song immediately appear in your list.

And if you see your database you’ll see the song isn’t there (duh! We’re offline), go ahead, refresh the browser, you’ll notice the new song is still there, turn on the internet and check your database :)

Keep In Mind

A few things to keep in mind:

  • Same methods, for real, that means you can do queries, work with lists, objects, CRUD, etc. All of that will have offline sync.
  • preserveSnapshot is not supported.
  • If writes are made offline followed by a page refresh, the writes will be sent when a connection becomes available.

Next Steps

If you have any questions don’t forget you can always leave a comment below.

If you want to take a deeper dive on Ionic + Firestore you should go through my FREE course: Build your first Firestore powered Ionic app.