Last year I wrote about using Couchbase Mobile in an Ionic Framework mobile application. Back then we were using Ionic Framework 1.0 and AngularJS 1.0. Technology has changed over the months and we’ve moved from what seems like ancient frameworks to much more modern iterations.

With Angular 2 released and Ionic 2 nearing stable release, I figured it would be a great idea to revisit what I’d done previously and explore Couchbase Mobile in an Android and iOS Ionic 2 application.

The Requirements

To make this project possible we’re going to need a few things installed and available. They are as follows:

  • Node.js 4.0+
  • Ionic Framework 2.0
  • The Android SDK or Xcode
  • Couchbase Sync Gateway

Ionic Framework uses the Node Package Manager (NPM) which ships with Node.js to handle all of the project dependencies. To build Android applications we’ll need the Android SDK installed and to build iOS applications we’ll need a Mac with Xcode installed. Finally, if we wish to demonstrate synchronization, we’ll need Couchbase Sync Gateway installed and available.

Creating a New Ionic 2 Project

We’re going to be building a very simple todo-list application with Ionic 2, Angular 2, and TypeScript. This todo-list will sync between devices and platforms as demonstrated in the animated image below.

Ionic 2 with Couchbase

This is the same application we saw in the Ionic Framework 1.0 tutorial as well as many other mobile tutorials. It is the same application because it serves as a very useful example.

To keep things simple, we’re going to start with a fresh project. From the Command Prompt (Windows) or Terminal (Linux and Mac), execute the following:

The above commands will create an Ionic Framework 2.0 project that uses Angular 2 and TypeScript. While I’ve chosen to add both the iOS and Android build platforms, we won’t be able to build for iOS unless we’re using a Mac with Xcode installed.

This project depends on the Couchbase PhoneGap plugin to function. Don’t be alarmed. While the name says PhoneGap, it is actually just an Apache Cordova plugin, something that is very compatible with Ionic 2. To install this plugin into the project, execute the following:

The Couchbase Lite plugin for Apache Cordova works entirely off of the RESTful APIs that are available. I personally would rather not work with APIs in my application, so I built a nice JavaScript wrapper to turn the APIs into a pleasant class. The wrapper,cordova-couchbase, will let you use methods instead of worrying about HTTP requests to endpoints.

To install cordova-couchbase into your project, execute the following:

At this point we’re ready to start developing the Ionic 2 application.

Managing Couchbase via an Angular 2 Provider

When working with databases in an Angular 2 application, it is a good idea to keep them in a service, also known as a provider. This allows us to not only bootstrap a lot of the database logic in a single file, but keep our database layer segregated from the rest of our code.

Using the Ionic CLI, execute the following to generate a provider class:

Essentially, the command just creates a directory and file at src/providers/couchbase-provider.ts within the project. This provider should look something like the following:

Let’s start thinking about how our Couchbase service will work and the bits and pieces of code that will go into it to make it a success.

We want our database service to act as a singleton, meaning we want one single database class to be instantiated for the entire application. Sort of like a shared service. We can configure this through the constructor method of our provider:

So what is happening in the above code so far? First we created two private variables. The boolean will tell us if the database has already been instantiated. The Database variable will hold the currently open database.

Inside the constructor method itself, we are doing our conditional logic check. Because the Apache Cordova plugin uses native code we need to make sure the device is ready. This is demonstrated through the use of Ionic’s platform.ready method. Once the device is ready we can open a database, even if it doesn’t exist, and set it to our private variable.

The open database can be retrieved from our provider using the above getDatabase method.

We’re not done with the CouchbaseProvider class yet. We should probably think about creating our MapReduce views for future querying and setup our change listener. All of this will happen within the constructor method after setting the open database.

For example, now lets take the following:

In the above code we’ve added a listener variable that will emit changes that can be subscribed to in our Angular 2 code. Within the constructor method we create a MapReduce view called items with logic that will emit key-value pairs only if the document contains a property called type that equals “list” and a property called title that can equal anything.

The view is then added to a design document of our choosing and the listener is enabled. With the listener enabled, any changes to the database will trigger it. This means if we add a document, change a document, or delete a document, the listener will emit the change.

The listener can be accessed from various pages in the application by calling the getChangeListener function.

The provider is created, but it isn’t currently being shared across the application. To do this we need to import it into the Angular 2 @NgModule block found in the project’s src/app/app.module.ts file. This file will look something like the following when finished:

Notice the provider was imported and added to the providers array? Now we can focus on adding application logic.

Using Couchbase within the Ionic 2 Application

It is probably a good idea to open our database when the application launches. While we could do this when the first page loads, we don’t have to.

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

In the above code we imported the provider and injected it into the constructor method. This will trigger before the first page loads, opening the database, creating the view, and starting the listener.

From here on out we’re going to spend our time in the first and only application page. This means we’ll be spending our time in the project’s src/pages/home/home.ts and src/pages/home/home.html files.

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

We’re going to break down what this means and add each of the methods one by one.

You can see that we’re importing the CouchbaseProvider along with other components. We’ll explore what each means as we get there.

The items array that is public will hold all of our todo-items that will be presented in the UI, hence why it is public. The constructor method has many injections for each of the components we plan to use. It is also where we initialize our public array.

It is never advisable to load data in the constructor method, which is why we have the ionViewDidEnter method. This method is where most of the heavy lifting happens:

First you’ll notice the timeout. We’re working with a lot of asynchronous components, specifically the Couchbase component. Often there is a race condition where the database won’t be ready in time for when we wish to use it. Adding a simple timeout for 100ms is more than enough to get the ball rolling. There are other ways to do this, but the timeout is my preference.

When the page loads we want to subscribe to our listener that was created in the provider. Any data emitted we’ll loop through. In this particular example we are ignoring deletes and treating changes and additions the same. In your application you may want to add more specific logic. Essentially I am saying that as long as the change was not a delete, we are going to take the key that was changed and do a lookup on the document. If the document is one of our todo documents we want to add it to the public array.

So what is going on with the zone stuff? Emitters can get weird so when we receive an event, we want to update the Angular 2 zone. You may find this not necessary, but if the UI doesn’t update with the changes, not having the zone stuff is why.

After the change listener has been crafted, we want to query the database as it stands right now. This is where the refresh method comes into play:

The refresh method will query our view and add each of the result items into our public array. We only need to query once because the changes that come in will automatically be added for us as a convenience.

The add method is the final method of this Ionic 2 page:

When executed, a prompt will display. When the user enters information into the prompt, it will be saved as a document within Couchbase. The change listener will pick up this local change and add it to the list.

The simple UI behind this application, found in the src/pages/home/home.html file, looks like the following:

The UI has an action bar with a button for displaying the prompt. The core content is a list view where we loop through the public array from the TypeScript file.

Synchronization Between Devices and Platforms

Up until now everything has been local to one device. Nothing we’ve added so far has been responsible for synchronization with Couchbase Sync Gateway or other devices. However, adding sync support requires hardly any effort.

Open the project’s src/providers/couchbase-provider.ts file and include the following line after opening the database:

Of course swap out the hostname and database name with that of your remote Sync Gateway instance. Now your application will continuously sync. Isn’t it awesome that one line of code gave us synchronization support?

If you wish to spin up a simple Sync Gateway instance, here and now, create the following sync-gateway-config.json file:

When you start Sync Gateway, point it at that particular configuration file. Update your sync function in the Ionic 2 application to match the host and database.

Taking the Finished Project for a Test Drive

I understand if this guide was a bit lengthy. I’ve gone ahead and published a sample project to GitHub that you can run and review to compliment this tutorial.

Clone the project by executing:

With the project downloaded, we need to restore the project dependencies, plugins, and platforms. Execute the following to restore those dependencies:

Now you can proceed to running the application in your device or simulator. Just don’t forget to run Couchbase Sync Gateway and update the sync method to reflect that of your remote setup.

Conclusion

You just saw how to create a cross platform iOS and Android hybrid mobile application with Ionic 2 that uses Couchbase Mobile. This is a step up and revisit from my previous article that demonstrated Ionic Framework 1.0 and Couchbase Mobile.

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.

17 Comments

  1. Hi Team,

    i am trying to run the app and getting alert in the home screen as “Couchbase Lite is not installed”

    even i have installed the below plugins.

    cordova plugin add cordova-plugin-whitelist

    cordova plugin add https://github.com/couchbaselabs/Couchbase-Lite-PhoneGap-Plugin.git

    1. Are you trying to use live-reload, ionic serve, or ionic view? Native plugins cannot be emulated in that fashion, they need to be installed on the actual device or simulator from binary.

      Can you confirm you’re not doing one of those three?

  2. Thanks for your quick response.

    When i run the command “ionic cordova run android” I got below message while it compiling. I am giving the screen shot link also

    https://firebasestorage.googleapis.com/v0/b/tw-chatapp.appspot.com/o/Capture.PNG?alt=media&token=c3bfa5d6-8246-4196-9a89-7ef6941502a4

    [13:03:02] tslint: E:/E WORKS/CouchBase/src/pages/home/home.ts, line: 4
    Unused import: ‘Couchbase’
    L3: import { CouchbaseProvider } from “../../providers/couchbase/couchbase”;
    L4: import { Couchbase, Database } from “cordova-couchbase/core”;
    [13:03:02] tslint: E:/E WORKS/CouchBase/src/pages/home/home.ts, line: 4
    Unused import: ‘Database’
    L3: import { CouchbaseProvider } from “../../providers/couchbase/couchbase”;
    L4: import { Couchbase, Database } from “cordova-couchbase/core”;

    After launch the app i got below error.
    https://firebasestorage.googleapis.com/v0/b/tw-chatapp.appspot.com/o/mobile.PNG?alt=media&token=e24e91f7-dce9-4c0c-a258-844001d72f0c

    Looking forward to your response.
    Thanks.

  3. Hello,

    I am trying to follow this example, but I cannot install the Couchbase-Lite-PhoneGap plugin.
    When i try to add it using
    “ionic cordova plugin add https://github.com/couchbaselabs/Couchbase-Lite-PhoneGap-Plugin.git
    I get an error that there is either a connection problem or the plugin spec is incorrect. It’s not a connection problem, I can add other plugins from github with the same command.
    When I try to bypass the problem and download and unzip the plugin manually, and add it as a local plugin with the path to the folder, i get an error that a valid package.json is missing.

    1. The command is either ‘ionic plugin add’ or ‘cordova plugin add’. There is no such ‘ionic cordova plugin add’ command.

      Best,

      1. Actually the ionic plugin command has been renamed to ionic cordova plugin.
        “ionic cordova plugin add https://github.com/couchbaselabs/Couchbase-Lite-PhoneGap-Plugin.git” is the right command to install the plugin, and I don’t know how to fix Marburg problem.

      2. I finally succeeded setting it up now.
        But when I try to ionic serve -l the app, I get a this.couchbase.getDatabase(…) is undefined.

        1. You cannot serve this plugin because it is native. It must be compiled and installed as if you were doing it for real.

          1. Of course! Thx for the feedback. It makes it more difficult to develop and live-reload, but I guess that can also be done in emulate mode.

          2. unexpected end of JSON input at
            Couchbase()).openDatabase(“todolite”).then(……

            [16:54:48] console.log: Ionic Native: deviceready event fired after 2325 ms
            [16:54:48] error opening ws message: {“category”:”console”,”type”:”log”,”data”
            [“DEVICE READY FIRED AFTER”,2152,”ms”]}
            [16:54:48] console.error: ERROR
            [object Object]
            [16:54:48] console.error: ERROR
            [object Object]

  4. hello Nic Raboy,

    I’m beginner to Couchbase and want to develop multi user hybrid mobile application in ionic with data synchronization.
    I already develop android(native) app with MySQL as back-end and willing to convert that MySQL database with Couchbase for offline support. So what things should I follow and how to convert MySQL database into Couchbase.
    Thanks in advance

  5. screenshot of the error with all the details.
    I commented out connecting to the sync_gateway, so it is already in setting up the local database, that the json error occurs.

    https://drive.google.com/file/d/0B0KRHtKNSw4xUXdfMWhEcU16Nms/view?usp=sharing

    1. It is inside the cordova-couchbase wrapper. I have added those files to the project now and call them locally.
      So far i am able to track it down to database.ts method makeRequest.

      1. Ok, went as far as i could.
        pulling the cordova-couchbase wrapper inside the project, and fixing the #3 bug, as Murilo Perrone did, fixed the json parse error, but it doesn’t make the demo work.
        I added some debugging info to the console.log, so the deviceready event really is fired, after 13 seconds,
        the couchbase.openDatabase() calls the database.getDatabase(), which calls the makeRequest method with method GET and url http://c3c19c87-dcc1-4b6d-a3db-fc7be65a427f:7adfa00d-0fd7-44ea-95b9-3cbe7f0609dd@localhost:5984/councilapp

        That all seems to go well. It just doesn’t seem to return anything, because further on, this.couchbase.getDatabase() stays undefined,
        cannot read queryView of undefined,
        cannot read getDocument of undefined.

        So i have tried for 3 days, with the limited knowledge that I have, but I just cannot make it work any more. This is probably the point where I’ll give up.

        17:39:22] console.log: Angular is running in the development mode. Call enableProdMode() to enable the production
        mode.
        17:39:23] console.log: deviceready has not fired after 5 seconds.
        17:39:23] console.warn: Ionic Native: deviceready did not fire within 5000ms. This can happen when plugins are in an
        inconsistent state. Try removing plugins from plugins/ and reinstalling them.
        17:39:23] console.warn: Native: deviceready did not fire within 5000ms. This can happen when plugins are in an
        inconsistent state. Try removing plugins from plugins/ and reinstalling them.
        17:39:23] console.log: Ionic Native: deviceready event fired after 12030 ms
        17:39:23] console.log: DEVICE READY FIRED AFTER 11374 ms
        17:39:23] console.log: method: GET, url:
        http://c3c19c87-dcc1-4b6d-a3db-fc7be65a427f:7adfa00d-0fd7-44ea-95b9-3cbe7f0609dd@localhost:5984/councilapp
        17:39:26] console.error: ERROR [object Object]

  6. The reason why it’s not working for me is in the cordova-couchbase wrapper.
    In line18 of the couchbase.ts of that project, a promise is made with database.getDatabase().then(result……)
    in line 21, you catch the possible errors, but you assume error.status exists.
    In my case, the error itself is null, hence all the rest also fails.

    1. Got a version working.
      Now I notice that the plugin does not play well with –livereload.
      The app works when I run it in an emulator without livereload.
      The plugin crashes on the first action performed on the plugin when I run it in an emulatir with livereload.

  7. DEVICE READY FIRED AFTER 590 ms
    Couchbase Lite is not installed!
    EXCEPTION: Cannot read property ‘queryView’ of undefined
    ORIGINAL STACKTRACE:
    TypeError: Cannot read property ‘queryView’ of undefined
    at t.refresh (file:///android_asset/www/build/main.js:10:22154)
    at file:///android_asset/www/build/main.js:10:22067
    at t.invokeTask (file:///android_asset/www/build/polyfills.js:3:14051)
    at Object.onInvokeTask (file:///android_asset/www/build/main.js:3:29640)
    at t.invokeTask (file:///android_asset/www/build/polyfills.js:3:13987)
    at e.runTask (file:///android_asset/www/build/polyfills.js:3:11411)
    at invoke (file:///android_asset/www/build/polyfills.js:3:15164)

    Please see this screenshot
    http://prntscr.com/gy09lz

Leave a reply