Not too long ago I wrote about using Couchbase in an Ionic 2 application. In the previous example we saw how to use Couchbase Lite and the RESTful API for saving data and working with Couchbase Sync Gateway. While that is the preferred approach, it isn’t the only approach.

There is a great JavaScript library called PouchDB that can actually connect to Couchbase Sync Gateway, pulling Couchbase Lite out of the equation. This means that PouchDB can be used with Ionic 2 to synchronize data between Couchbase Server and any application that was created.

So how do we make this happen?

The Requirements

If you saw the previous tutorial, the requirements here will be no different. They are as follows:

  • Node.js 4.0+
  • Ionic Framework 2.0
  • Couchbase Sync Gateway
  • Android SDK for Android and Xcode for iOS

The Ionic Framework 2.0 CLI is used for creating and building applications. It uses the Node Package Manager (NPM) found with Node.js to download all the dependencies. We won’t be syncing with Couchbase Server in this example, but we’ll still be using Couchbase Sync Gateway. The plan here is to make use of the in-memory option that Sync Gateway has for prototyping. Including Couchbase Server isn’t difficult after this.

Preparing Couchbase Sync Gateway

Couchbase Sync Gateway handles all the orchestration of data between devices, platforms, and Couchbase Server. This includes any read and write permissions. Because of this it needs to have its own configuration based on the needs of your application.

Take the following configuration for example:

The above configuration creates a database called example with no rules in terms of data channeling. This means that all devices will be able to read and write. Your needs may be different.

At the bottom of the configuration is information regarding cross origin resource sharing (CORS). The bottom bit is not necessary unless you plan to use features like ionic serve. Trying to access Sync Gateway from the same host, but different port will throw JavaScript errors. The CORS addition will prevent this. Again, this is only if you wish to serve the application in your web browser. Running the application from your device will have no issues.

Creating an Ionic Framework with PouchDB Application

The application we create will match that of what we created previously with Couchbase Lite and Ionic 2. We will be building a simple todo list application that synchronizes the items between devices.

Couchbase with Ionic 2 and PouchDB

This is a single page application, but it covers all the necessary Ionic 2 and Angular 2 best practices. To create this project, execute the following from your Command Prompt (Windows) or Terminal (Mac and Linux):

The above commands will create a fresh Ionic 2 project that uses Angular 2 and TypeScript. While I’ve gone ahead and added both the Android and iOS build platforms, you won’t be able to build for iOS unless you’re using a Mac with Xcode installed.

Since this project will be using PouchDB, it needs to be installed into our project. This can be done by executing the following command:

PouchDB is a JavaScript project and it doesn’t have proper support for TypeScript. This is not an issue as we can get around the hurdle of missing type definitions. However, we’re going to need to obtain type definitions for another library that will load the plugin.

From the command line, execute the following:

Installing the Node.js type definitions will allow us to use the require keyword which is essential when importing JavaScript dependencies.

There is one more JavaScript dependency for our project, but this time we don’t have to worry about the type definitions not existing. We need to install a library for generating unique id values which will represent our document keys. This library can be installed through the following command:

The above command will install the library and its type definitions for TypeScript.

At this point we can focus on the development of our application!

Developing the Angular 2 Shared Provider

It is good practice in any Angular 2 application to keep database related activity separated in what is known as a shared provider or shared service. This allows us to have a singleton database instance and keep our database code out of the page logic.

To create a provider in Ionic 2, execute the following command:

The above command should create a file at src/providers/pouchdb-provider.ts that we can work with. Open this new file and include the following code:

Before we start populating each of the methods, let’s break down what we have so far.

This provider will be injectable in each of the pages we wish to use it. Because PouchDB allows us to sync changes we want to be able to emit those changes and subscribe to them, thus the need for the EventImitter import. The PouchDB library is imported like standard JavaScript.

We only want to keep one database instance open and we can do that by making use of an isInstantiated variable. This is done in the constructor method like so:

With an open database we want to be able to work with the data. PouchDB has its own APIs for working with data, but being that it is vanilla JavaScript, certain things should be enhanced in our provider to make it more Angular 2 friendly.

Fetching all data can be done using the allDocs method in PouchDB. By including the include_docs property, the document data is included rather than just id values.

If you know the id of the document you’re after then you can do a lookup directly rather than querying for all the documents. Saving documents is where things can get a little confusing:

In the above put method we have a way for creating or updating a document. Documents that have no revision are created, otherwise they are updated. This is possible by first doing a lookup on a document by its id. If the document exists, use the revision and update it, otherwise create it.

Without synchronization you aren’t technically using Couchbase in your stack. Also, there are much better solutions for data than PouchDB if you’re only looking for a local database. With that said, the above sync function will allow you to connect to a remote database. Our remote database is actually a running Sync Gateway instance. We are choosing to do a two-way sync with Sync Gateway and emitting the changes to the EventEmitter in Angular 2.

When we wish to subscribe to those changes we must first obtain a copy of the listener that is emitting them.

At this point the Angular 2 provider is complete, but not ready to be used. It needs to be added the project’s @NgModule block found in the src/app/app.module.ts file. The file would look something like the following:

Notice how the provider was imported and then added to the providers array. It can now be used in each page of our application.

Adding PouchDB Logic for Saving and Syncing

The rest of our application is actually quite simple now that we’ve laid the foundation to our data layer. Remember this is a very simple application, but heavily data driven.

Open the project’s src/pages/home/home.ts file and include the following code:

In the above code we are importing various Ionic and Angular 2 components as well as our PouchDB provider and UUID library. Many of these components are injected in the constructor method. The constructor method also initializes our public array which will be bound to the UI. This array will contain the data we sync with PouchDB.

While we can initialize our variables in the constructor method, it is never a good idea to load data into them in the constructor method. Instead we should use the Ionic ionViewDidEnter method:

In the above ionViewDidEnter method we are starting the two-way sync with PouchDB and Couchbase Sync Gateway. The hostname is that of my currently running Couchbase Sync Gateway instance. The database does not need to match that of my local database.

When we are syncing we are also going to subscribe to the change listener. This is a simple application so we won’t worry about changing or deleting data, only adding data. Listeners can be a little iffy in Angular 2 where as there becomes a disconnect between the UI and the data. This disconnect can be corrected by adding the listener data into a zone.run method.

With the application subscribing to changes, we need to do a first-time query of the data when the application opens. We want to fetch all the data and add it to our public array.

The last method we have is the insert method and it is mostly Ionic driven:

Here we craft a prompt popup. When the save button is pressed, the text in the form is saved with PouchDB. The id of the document is uniquely generated with the UUID library.

So what does our UI look like?

Creating a Simple UI with HTML

The UI is the easy part because the application is so simplistic. Open the project’s src/pages/home/home.html file and include the following HTML markup:

The UI has an action bar with a button, that when pressed will trigger the insert method found in our TypeScript. The core content of the UI is a list that loops through the public array printing each item to the screen.

Taking the Project for a Test Run

We went over many concepts and a lot of code. To make life easier, I uploaded a working project to GitHub that you can download and test out for yourself.

With the project downloaded, execute the following commands to restore the dependencies, plugins, and platforms:

As long as you don’t forget to update the sync method found in the project’s src/pages/home/home.ts file with your Sync Gateway host, the project should be runnable.

Conclusion

You just saw how to create an Android and iOS application that syncs using Ionic 2, PouchDB, and Couchbase. This is an alternative method to the previous guide that I wrote which uses Couchbase Lite.

Posted by Nic Raboy, Developer Advocate, Couchbase

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.

Leave a reply