Last year I wrote an article that explained how to synchronize between platforms and Couchbase with only AngularJS and PouchDB. Back then AngularJS was booming and probably my favorite framework of all time. A year later AngularJS is still around, but is slowly being replaced by Angular 2, the next version of the popular framework. After using Angular 2, I look back at AngularJS 1.0 and wonder what was going through my brain because Angular 2 is pure awesomeness.

This time around we’re going to see how to create a simple web application that syncs using only Angular 2, PouchDB, and Couchbase Mobile.

The Requirements

The few requirements to being successful with this project are as follows:

  • Node.js 4.0+
  • Angular 2 CLI
  • Typings
  • Couchbase Sync Gateway

The Angular 2 CLI can be installed using the Node Package Manager (NPM) which is included with Node.js. NPM is also used when it comes to gathering various project dependencies. We won’t be using Couchbase Server in this example, but we could. Instead we’re only going to use Couchbase Sync Gateway and its prototyping features.

Configuring Couchbase Sync Gateway

Couchbase Sync Gateway is necessary to handle all of the synchronization. Without it we only have local storage in our web application, and in all honesty, there are much better solutions than PouchDB if you only wanted local storage.

Download the latest Sync Gateway and deploy it with the following configuration:

Save this to a file called sync-gateway-config.json if you wanted. This is a very basic configuration where we are using an in-memory database called example. There are no read and write permissions so anything goes. At the bottom of this configuration we have some items relating to cross origin resource sharing (CORS). Because we’ll be serving our application locally, we need to identify this to prevent JavaScript errors.

Creating a New Angular 2 Project

To make things easy to understand we’re going to create a project with an incredibly simplistic design. We’re going to create a simple user management application where we can add people and they will be synchronized to wherever you want. For example, check the animation below:

Couchbase with PouchDB and Angular 2

In the above animation we have two web browsers. Add a person to one and it will synchronize to the other. This is something that would be particularly difficult without Couchbase.

Let’s start by creating a fresh Angular 2 project using the Angular CLI. Execute the following from your Command Prompt (Windows) or Terminal (Mac and Linux):

It may take a while, but when the project is created we want to install PouchDB and any necessary dependencies. Execute the following to install the latest PouchDB:

The maintainers of PouchDB have mixed emotions when it comes to TypeScript, a critical technology when it comes to Angular 2 development. For this reason there are no reliable type definitions available. This is not a big deal though.

Using Typings, we are going to install the following:

The above type definitions will allow us to use the require keyword within TypeScript. With it we can import the downloaded PouchDB into our project.

At this point we can start developing our project!

Developing an Angular 2 Provider to Maintain the Data

When working with data it is always a good idea to create an Angular 2 service, also known as a provider. This allows us to have a singleton instance and a class that is segregated from the rest of our code. It is great from a maintainability perspective.

You can create the provider manually or using the CLI. From the CLI, execute the following:

Two files should be created in your project’s src/app directory. You should have a pouchdb.service.ts and a pouchdb.service.spec.ts file. They may be named something similar, but the name isn’t really important.

The spec file is a unit testing file, something we won’t worry about in this particular example. Instead we’re going to start developing in the pouchdb.service.ts file.

Open the file and include the following TypeScript code:

Before we start filling in each of the methods, let’s figure out what we’re trying to do. We only want one database instance while the application is running. This can be accomplished via the constructor method:

In this case the local database is called nraboy. Now PouchDB does have a really great API. It just isn’t Angular 2 optimized, meaning working with PouchDB in its vanilla state in our project could have some hiccups.

In the scenario where we want to fetch all local documents, we might do something like this:

We use the include_docs attribute so the documents get included in the results rather than just their id values. So maybe we only want to get a single document. We would do something like the following:

So far we have been using the PouchDB API exactly how the documentation recommends. How about changing it up a bit? The API offers a way to create or update documents, but let’s combine this in a single method?:

The above put method will check to see if a document exists based on its id. If it exists, copy the revision into the new data and save it again. If the document doesn’t exist, create it without a revision.

You probably noticed the EventEmitter that was included near the top. This is necessary for subscribing to change events in the Angular 2 pages. Take the following sync method for example:

Here we are defining a remote data source, which will be Couchbase Sync Gateway, choosing to do a live two-way sync, and emitting the changes every time they are discovered.

The change listener can be accessed on every page by accessing the following:

The the above we’d just end up subscribing to the listener.

While the provider is created, it isn’t available across all pages yet. We need to import it into the project’s @NgModule found in the src/app/app.module.ts file. This file will look something like the following:

Notice we’ve imported the provider class and added it to the providers array of the @NgModule block. Now we can use the provider throughout the application.

Applying the Database Provider within the Angular 2 Application

To keep things simple, this will be a single page application. We’re going to spend the rest of our time in the project’s src/app/app.component.ts and src/app/app.component.html files.

Open the project’s src/app/app.component.ts file and include the following TypeScript code:

You’ll notice that we’re importing the PouchDBService along with a few other things. We’ll explore those as we hit them.

Inside the AppComponent we have a public array called people which will be bound to our UI. It will contain all the data being saved and synced. The form variable will represent an object containing each of our form elements. We could split it up into strings, but an object is more convenient because we’re going to end up saving the entire object as a document in Couchbase.

In the constructor method we inject our PouchDB service and NgZone. We use NgZone to refresh the Angular 2 zone which sometimes gets bent out of shape when working with events and other kinds of listeners. Not too big a deal as you’ll see soon. Finally, the constructor method initializes our two variables.

It is bad practice to load data in the constructor method so instead we use the ngOnInit method:

Most of the application grunt work happens above. In the above code we are defining our remote Sync Gateway host and database name. It doesn’t need to match that of our local database. We then subscribe to our listener and loop through the changes as they come in. All changes are added to the public array within an NgZone so they refresh on the screen.

Since change events only trigger as they happen, we need to fetch all the documents when we first initialize the application.

This brings us to the insert method:

If our form elements are not blank then we can save the data as a document in the database. Once saved, the change event will trigger and the data will be added to the public array and displayed on the screen.

This is all seamless between the web application and Couchbase Sync Gateway.

Taking it for a Test Drive

There is a lot to take in when it comes to this Angular 2 and PouchDB guide. I uploaded a working project to GitHub if you’d like to take it for a spin.

Download the project and execute the following from your Terminal or Command Prompt:

The above command will grab all the project dependencies. Make sure to update the src/app/app.component.ts file to reflect the correct hostname of your Sync Gateway and you should be good to go.

The project can be executed by running:

While serving, the project can be accessed from http://localhost:4200.

Conclusion

You just saw how to build a simple web application that syncs data using PouchDB and Couchbase. This is an Angular 2 application that is a step up from the guide I wrote last year which used AngularJS 1.0.

Author

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.

3 Comments

  1. Hey mate! thank you for the tutorial, really appreciate it. Just one quick one, i’m trying to install “require” as per the suggested command but not having much luck. I’m running Angular 5.

    typings install dt~require –save –global

    On “ng serve” i get the following:

    “ERROR in src/app/services/pouchdb.service.ts(3,17): error TS2304: Cannot find name ‘require’.”

    Any ideas?

    1. I’m having the same problem! I managed to find some outdated npm packages, including the old angular-cli that needed to be removed and replaced with @angular/cli, I’m wondering if it’s something similar because when I installed the typings, I got a notice that it’s deprecated in favor of using @types. I’ll give that a try…

  2. PouchDB works with TypeScript now, without using require.js. See the PouchDB documentation: https://pouchdb.com/guides/setup-pouchdb.html#typescript

    Steps:
    1. Install PoutchDB
    > npm install pouchdb –save
    2. Install PouchDB types
    > npm install pouchdb @types/pouchdb
    3. Edit tsconfig.json and enable synthetic default imports
    {
    “compilerOptions”: {
    “allowSyntheticDefaultImports”: true
    }
    }
    4. Import the PouchDB in you Typescript class: pouchdb.service.ts.
    import PouchDB from ‘pouchdb’;

Leave a reply