Back to Blogs

Querying for Couchbase Documents in a NativeScript Angular Mobile Application

Nic Raboy of Couchbase Published

Filter blogs by:

I recently wrote about using Couchbase as a key-value store in a NativeScript iOS and Android application built with Angular. In this example we saw how to collect user profile information to be saved or loaded from Couchbase on the mobile devices. However, we were saving and loading based on a particular key, not querying based on document properties.

What if you have NoSQL documents where you don't know the key and you need to query based on the document properties? In this example we're going to take the previous article to the next level.

NativeScript with Couchbase Profiles Example

We're going to bring our single page NativeScript application to multiple pages where the first page is a list of previously saved profiles and the second page allows you to create new profiles. Navigation between the pages will happen with the Angular Router.

The Requirements

The requirements between this guide and the previous remain the same. You'll need the following:

  • NativeScript CLI 2.0+
  • Android SDK and / or Xcode for Mac

The NativeScript CLI which is obtained through the Node Package Manager (NPM) will allow us to create and build mobile projects. To build and deploy actual Android and iOS applications you'll need either the Android SDK or Xcode or both.

Starting From Where We Left Off

We won't be building our project from scratch, but instead we'll be referencing the previous NativeScript with Couchbase tutorial. However, a lot of what you see here will be a review.

The previous project should be a basic one page application with the nativescript-couchbase plugin installed. We need to bring our single page into multiple pages.

Preparing Multiple Application Pages for Navigation

We will be using two pages in addition to the modal that we had previously created. Within your project, create the following files and directories:


The above files will represent our two pages. To be successful with the Angular Router we need to create a routing file that links these files together.

Create the following within your project:


While we haven't created our page classes yet, we're going to focus on linking them together. Open the project's app/app.routing.ts file and include the following:

import { ProfileListComponent } from "./components/profile-list/profile-list";
import { ProfileComponent } from "./components/profile/profile";

export const appRoutes: any = [
    { path: "", component: ProfileListComponent },
    { path: "profile", component: ProfileComponent }

export const appComponents: any = [

As you can guess we're going to have a ProfileListComponent and a ProfileComponent. When it comes to appRoutes, the default page is the one with an empty route path. The second page will be navigate-able via the profile path.

Adding each of the components to an array is a convenience for the next step.

Open the project's app/app.module.ts file because we need to configure the router to use the routing file we had just created.

import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/platform";
import { NativeScriptFormsModule } from "nativescript-angular/forms";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { ModalDialogService } from "nativescript-angular/modal-dialog";

import { appComponents, appRoutes } from "./app.routing";
import { AppComponent } from "./app.component";
import { ModalComponent } from "./app.modal";

    declarations: [AppComponent, ModalComponent, ...appComponents],
    entryComponents: [ModalComponent],
    bootstrap: [AppComponent],
    imports: [
    providers: [ModalDialogService],
    schemas: [NO_ERRORS_SCHEMA]
export class AppModule { }

Notice in the above that we still have all the modal related items from the previous tutorial. This time around we've imported from the app/app.routing.ts file and injected into the imports and declarations array of the @NgModule block.

The parent page for our routing system is the AppComponent class we were using in the previous example. We need to wipe it out.

Open the project's app/app.component.html file and include the following XML markup:


To pair with this we can remove most of the code within the app/app.component.ts file. This file should look similar to the following in the end:

import { Component } from "@angular/core";

    selector: "my-app",
    templateUrl: "app.component.html",
export class AppComponent { }

At this point we can start developing each of our application pages. For more information on routing using the Angular Router, visit a previous article I wrote on the subject.

Moving the Code from the Previous Couchbase NativeScript Example

Remember all the code I just told you to wipe out? I probably shouldn't have said that, but lucky for us you can copy and paste it from the previous example, or better yet, below.

We need to take the code that was previously in the app/app.component.ts and app/app.component.html files and move it to the new app/components/profile/profile.ts and app/components/profile/profile.html files.

Open the app/components/profile/profile.html file and make it look like the following:

<ActionBar title="{N} Profile"></ActionBar>
<GridLayout rows="*, *" cols="*">
    <Image [src]="" (tap)="showModal(true)" width="150" height="150" class="img-rounded" row="0" col="0"></Image>
    <StackLayout class="form" row="1" col="0">
        <StackLayout class="input-field">
            <Label text="First Name" class="label"></Label>
            <TextField [(ngModel)]="profile.firstname" class="input input-border"></TextField>
        <StackLayout class="input-field">
            <Label text="Last Name" class="label"></Label>
            <TextField [(ngModel)]="profile.lastname" class="input input-border"></TextField>
        <StackLayout class="input-field">
            <Button text="Save" (tap)="save()" class="btn btn-primary w-full"></Button>

The only thing that has changed in the above is that I removed the button in the action bar that was used for loading data. Now open the project's app/components/profile/profile.ts file and include the following:

import { Component, ViewContainerRef } from "@angular/core";
import { Location } from "@angular/common";
import { ModalDialogService } from "nativescript-angular/directives/dialogs";
import { Couchbase } from "nativescript-couchbase";
import { ModalComponent } from "../../app.modal";

    selector: "profile",
    templateUrl: "./components/profile/profile.html",
export class ProfileComponent {

    public profile: any;
    private database: any;

    public constructor(private modal: ModalDialogService, private vcRef: ViewContainerRef, private location: Location) {
        this.profile = {
            photo: "~/kitten1.jpg",
            firstname: "",
            lastname: ""
        this.database = new Couchbase("data");

    public showModal(fullscreen: boolean) {
        let options = {
            context: { promptMsg: "Pick your avatar!" },
            fullscreen: fullscreen,
            viewContainerRef: this.vcRef
        this.modal.showModal(ModalComponent, options).then((res: string) => {
   = res || "~/kitten1.jpg";

    public save() {


To be fair, I removed the load method that we had and included the Angular Location service for navigating backwards in the navigation stack. Everything, with the exception of paths, should be the same.

Remember, my application has avatar images of kittens that I found on the internet.

NativeScript with Couchbase Kittens

You should probably find your own avatar images and use them as appropriate. The ~/ represents that the images should be found in the project's app directory.

Now we need to have a look at the yet to be created page for listing data on the screen.

Querying for Profiles and Adding Them to a List on the UI

Our new page should, in theory, be simpler than everything we've done so far and in the previous guide. Open the project's app/components/profile-list/profile-list.ts file and include the following:

import { Component, OnInit } from "@angular/core";
import { Location } from "@angular/common";
import { Router } from "@angular/router";
import { Couchbase } from "nativescript-couchbase";

    selector: "profile-list",
    templateUrl: "./components/profile-list/profile-list.html",
export class ProfileListComponent implements OnInit {

    public profiles: Array<any>;
    private database: any;

    public constructor(private router: Router, private location: Location) { }

    public ngOnInit() { }

    public refresh() { }

    public create() { }


In the above we have a ProfileListComponent class with a public variable to hold all our UI bound data and a private instance to our Couchbase database.

We need to be able to navigate forward in the navigation stack and detect navigation backwards in the stack so we inject the Router and Location services into the constructor method. The constructor method also does the following:

public constructor(private router: Router, private location: Location) {
    this.database = new Couchbase("data");
    this.database.createView("profiles", "1", function(document, emitter) {
        emitter.emit(document._id, document);
    this.profiles = [];

In the above constructor method we open our database and create a new MapReduce view. This view is very simplistic in the sense it will return a key-value pair of all documents in the database. There is no conditional logic around what it returns in this scenario. The profiles MapReduce view is the foundation of our querying.

To query that view, we have the refresh method:

public refresh() {
    this.profiles = [];
    let rows = this.database.executeQuery("profiles");
    for(let i = 0; i < rows.length; i++) {

After querying we push each of the results into our public profiles variable. Don't get confused, the profiles variable is not the same as the profiles view.

public ngOnInit() {
    this.location.subscribe(() => {

The ngOnInit triggers after the constructor method. Not only do we execute our query, but we need to subscribe to navigation events so we can execute the query when returning to the page. This is because the constructor and the ngOnInit methods only trigger at load, not navigation backwards events.

Our last method is the create method:

public create() {

This will eventually be triggered by button press and it will take us to the second screen.

The UI for this page, found in the app/components/profile-list/profile-list.html, will look like the following:

<ActionBar title="{N} Profiles List">
    <ActionItem text="New" ios.position="right" (tap)="create()"></ActionItem>
    <ListView [items]="profiles" class="list-group">
        <Template let-profile="item">
            <GridLayout rows="auto" columns="50, *" class="list-group-item">
                <Image [src]="" width="50" height="50" row="0" col="0"></Image>
                <Label text="{{ profile.firstname }} {{ profile.lastname }}" row="0" col="1" class="label" marginLeft="10"></Label>

The <ListView> will iterate over each item in our public array and convert them into rows. Each row will be of two columns where the first image column has a 50 width, and the second column stretches to fit.


You just saw how to take your key-value NativeScript with Couchbase application to the next level by adding MapReduce view queries for querying data based on document properties. While the profile data doesn't do much, what if you wanted to sync what is stored in Couchbase on the device to other devices? We'll take a look at that next time.

«   Back to blogs