home ionic 1 tutorials ionic 2 tutorials
TRANSCRIPT
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 1/18
HOME IONIC 1 TUTORIALSIONIC 2 TUTORIALS
How To Use PouchDB + SQLiteFor Local Storage In Ionic 218 APRIL 2016 on Local Storage, Ionic 2, TypeScript, Angular 2, PouchDB,SQLite | Comments
A year ago I wrote a tutorial on how to use PouchDB +
SQLite for an Ionic 1 app. Now that Ionic 2 is in beta, I've
updated the tutorial for Ionic 2 and the recently released
Cordova SQLite Plugin 2.
The source code can be found on GitHub.
What is PouchDB?PouchDB is an open-source JavaScript library that uses
IndexedDB or WebSQL to store data in the browser. It's
inspired by Apache CouchDB and allows you to sync your
local data with a CouchDB server.
What I like about PouchDB is that it uses a NoSQL approach
to database storage, which greatly simpli¿es the code you
21Shares
8
4
Get updates for new Ionic 2 tutorials. SIGN UP HERE
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 2/18
need to write. And then there is the out-of-the-box
syncing with a server, but in this tutorial we'll only focus
on local storage.
There are storage limits for IndexedDB and WebSQL
databases, so if you want unlimited and reliable storage on
a mobile device, you're better o¼ using SQLite. PouchDB
will automatically use SQLite if you have installed a
Cordova plugin for it and have con¿gured it to use a
WebSQL adapter.
Note: SQLite is slower than IndexedDB/WebSQL as mentioned in
this article by Nolan Lawson.
Set up the librariesLet's start by creating our Ionic 2 app.
$ ionic start ionic2‐tutorial‐pouchdb blank ‐‐v2 ‐‐ts $ cd ionic2‐tutorial‐pouchdb
We'll have to install a couple of libraries into our app to get
PouchDB working with SQLite.
SQLite Plugin 2 for Cordova
PouchDB library
To install SQLite Plugin 2 execute the following command
in your Ionic app directory:
$ ionic plugin add cordova‐plugin‐sqlite‐2
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 3/18
Next, we'll install PouchDB.
$ npm install pouchdb ‐‐save
Because this tutorial is written in TypeScript, it would be
nice to have type de¿nitions for the PouchDB library, but
the ones on De¿nitelyTyped are over 2 years old, so let's
skip that.
If we want to import the PouchDB library without the help
of type de¿nitions, we need to use require() , so let's install
the type de¿nition for it:
$ typings install require ‐‐ambient ‐‐save
Tip: If you want to know more about using external libraries in
Ionic 2, check out this blog post by Mike Hartington.
We are done with setting up the necessary libraries, you
now have everything you need to start writing code!
What are we going to build?Our app is going to be a birthday registration app that will
have add, update, delete and read functionality.
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 4/18
Create database serviceLet's go ahead and create a service to encapsulate our
PouchDB calls in app/services/birthday.service.ts.
import {Injectable} from 'angular2/core'; let PouchDB = require('pouchdb'); @Injectable() export class BirthdayService { private _db; private _birthdays; initDB() { this._db = new PouchDB('birthday2', { adapter: 'websql' }
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 5/18
}
We need to initialize the database, if it doesn't exist, a new
database will be created.
As you can see we're setting the adapter to WebSQL, the
way PouchDB works is that if you have the SQLite plugin
installed, it will automatically use that, otherwise it will fall
back to WebSQL.
Add a birthdayLet's write the code for adding a birthday to our database.
add(birthday) { return this._db.post(birthday); }
Is that all? Yes, that is all you have to do!
We don't need to write a SQL INSERT statement and map the
data to a SQL table. In PouchDB the birthday object is
simply serialized into JSON and stored in the database.
There are 2 ways to insert data, the post method and the
put method. The di¼erence is that if you add something
with the post method, PouchDB will generate an _id for
you, whereas if you use the put method you're generating
the _id yourself.
Update a birthday
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 6/18
Update a birthday
update(birthday) { return this._db.put(birthday); }
Delete a birthday
delete(birthday) { return this._db.remove(birthday); }
Get all birthdaysLet's get all the birthdays saved in the database.
getAll() { if (!this._birthdays) { return this._db.allDocs({ include_docs: true}) .then(docs => { // Each row has a .doc object and we just want to send an // array of birthday objects back to the calling controller, // so let's map the array to contain just the .doc objects. this._birthdays = docs.rows.map(row => { // Dates are not automatically converted from a string. row.doc.Date = new Date(row.doc.Date); return row.doc; });
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 7/18
// Listen for changes on the database. this._db.changes({ live: true, since: 'now' .on('change', this.onDatabaseChange); return this._birthdays; }); } else { // Return cached data as a promise return Promise.resolve(this._birthdays); } }
We use the allDocs function to get an array back of all the
birthday objects in the database. I don't want the code that
will be calling this service to know anything about docs or
PouchDB, so I've mapped the rows array to a new array that
only contains the row.doc objects.
As you can see there is also a conversion of the row.doc.Date
property to an actual Date , because unfortunately, the
dates in JSON will not be automatically converted back to
Date objects.
I also save the output in the _birthdays array so the data
will be cached and I will only have to get the data from the
database one time on start of the app.
"But...", you ask, "how will I keep that cached data in sync with
the database when there is data added or changed?"
Well, I'm glad you asked, that's where the onDatabaseChange
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 8/18
function comes in.
private onDatabaseChange = (change) => { var index = this.findIndex(this._birthdays, change.id); var birthday = this._birthdays[index]; if (change.deleted) { if (birthday) { this._birthdays.splice(index, 1); // delete } } else { change.doc.Date = new Date(change.doc.Date); if (birthday && birthday._id === change.id) { this._birthdays[index] = change.doc; // update } else { this._birthdays.splice(index, 0, change.doc) // insert } } } // Binary search, the array is by default sorted by _id. private findIndex(array, id) { var low = 0, high = array.length, mid; while (low < high) { mid = (low + high) >>> 1; array[mid]._id < id ? low = mid + 1 : high = mid } return low; }
Inspired by this post: E覹䶘ciently managing UI state with
PouchDB.
This function allows you to update the _birthdays array
whenever there is a change on your database. The input for
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 9/18
this method is a change object that contains an id and the
actual data in a doc object. If this id is not found in the
_birthdays array it means that it is a new birthday and we
will add it to the array, otherwise it's either an update or a
delete and we make our changes to the array accordingly.
Let's build the UIOK, so we have the service set up which does most of the
heavy work, let's have a look at the UI.
We'll create 2 pages for our app, one to display the list of
birthdays (HomePage) and one to add or edit a birthday
(DetailsPage).
Before we do the implementation of the pages, we need to
set up our service as a provider. We can do that per page
but that means we will get a new instance of the service per
page and we won't be able to use the cached data.
So, let's add the service at the parent level, which in this
case is app.ts.
import {BirthdayService} from './services/birthday.service' @App({ template: '<ion‐nav [root]="rootPage"></ion‐nav>', config: {}, providers: [BirthdayService] })
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 10/18
Now we'll get a shared instance of BirthdayService in our
HomePage and DetailsPage .
HomePageWe'll implement the template home.html ¿rst, which uses
an <ion‐list> to display all the birthdays.
<ion‐navbar *navbar> <ion‐title> Birthdays </ion‐title> <ion‐buttons end> <button (click)="showDetail()"> <ion‐icon name="add"></ion‐icon> </button> </ion‐buttons> </ion‐navbar> <ion‐content class="home"> <ion‐list inset> <ion‐item *ngFor="#birthday of birthdays" (click)="showDetail(birthday)"> <div item‐left>{{ birthday.Name }}</div> <div item‐right>{{ birthday.Date | date:'yMMMMd' }} </ion‐item> </ion‐list> </ion‐content>
Angular 2 uses the Internationalization API to do date
formatting, which is pretty cool, but doesn't work in Safari.
So you have 2 options, you can either use this poly¿ll or
write your own date formatting pipes. For this tutorial we'll
use the poly¿ll, which means that you need to add this line
to your index.html.
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 11/18
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features
Now it's time to open up home.ts and write the code to get
the data from the service.
We'll wait for the platform.ready() event to ¿re before we
try to access the database. We then call
birthdayService.getAll() and because it's an asynchronous
call, we need to use zone.run() to let Angular know that it
needs to do change detection and update the view.
Tip: Watch the talk Angular 2 Change Detection Explained by
Pascal Precht.
import {Page, Modal, NavController, Platform} from 'ionic‐angular'import {BirthdayService} from '../../services/birthday.service'import {DetailsPage} from '../details/details'; import {NgZone} from 'angular2/core'; @Page({ templateUrl: 'build/pages/home/home.html' }) export class HomePage { public birthdays = []; constructor(private birthdayService: BirthdayService, private nav: NavController, private platform: Platform, private zone: NgZone) { } onPageLoaded() {
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 12/18
this.platform.ready().then(() => { this.birthdayService.initDB(); this.birthdayService.getAll() .then(data => { this.zone.run(() => { this.birthdays = data; }); }) .catch(console.error.bind(console)); }); } showDetail(birthday) { let modal = Modal.create(DetailsPage, { birthday: birthday this.nav.present(modal); modal.onDismiss(() => { }); } }
DetailsPageAdd a new page with this command:
$ ionic g page details ‐‐ts
Add the following code in details.html. For now I'm using a
plain text input type for the date, in the next beta release of
Ionic 2 there should be support for date pickers.
<ion‐navbar *navbar> <ion‐title>{{ action }} Birthday</ion‐title>
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 13/18
<ion‐buttons end *ngIf="!isNew"> <button (click)="delete()"> <ion‐icon name="trash"></ion‐icon> </button> </ion‐buttons> </ion‐navbar> <ion‐content padding class="details"> <ion‐list inset> <ion‐item> <ion‐label>Name</ion‐label> <ion‐input type="text" [(ngModel)]="birthday.Name </ion‐item> <ion‐item> <ion‐label>Birthday</ion‐label> <ion‐input type="text" [(ngModel)]="isoDate" placeholder </ion‐item> </ion‐list> <button block (click)="save()">Save</button> </ion‐content>
Add the following code in details.ts.
import {Modal, Page, NavParams, ViewController} from 'ionic‐angular'import {BirthdayService} from '../../services/birthday.service' @Page({ templateUrl: 'build/pages/details/details.html' }) export class DetailsPage { public birthday; public isNew = true; public action = 'Add'; public isoDate = ''; constructor(private viewCtrl: ViewController, private navParams: NavParams,
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 14/18
private birthdayService: BirthdayService) { } onPageLoaded() { this.birthday = this.navParams.get('birthday'); if (!this.birthday) { this.birthday = {}; } else { this.isNew = false; this.action = 'Edit'; this.isoDate = this.birthday.Date.toISOString() } } save() { this.birthday.Date = new Date(this.isoDate); if (this.isNew) { this.birthdayService.add(this.birthday) .catch(console.error.bind(console)); } else { this.birthdayService.update(this.birthday) .catch(console.error.bind(console)); } this.dismiss(); } delete() { this.birthdayService.delete(this.birthday) .catch(console.error.bind(console)); this.dismiss(); } dismiss() { this.viewCtrl.dismiss(this.birthday); }
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 15/18
}
We're Done!You can now test the app in the browser (where it will use
WebSQL).
$ ionic serve
And on your iOS and Android devices (where it will use
SQLite).
$ ionic run ios $ ionic run android
Inspecting the databaseThere is a Chrome extension called PouchDB Inspector that
allows you to view the contents of the database in the
Chrome Developer Tools.
The PouchDB Inspector only works for IndexedDB
databases and you'll need to expose PouchDB as a property
on the window object for it to work. Add this line of code to
the BirthdayService implementation.
window["PouchDB"] = PouchDB;
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 16/18
You can not use the PouchDB Inspector if you loaded the app
with ionic serve ‐‐lab because it uses iframes to display the
iOS and the Androw views. The PouchDB Inspector needs to
access PouchDB via window.PouchDB and it can't access that when
the window is inside an <iframe> .
TroubleshootingKeep in mind that if you haven't speci¿ed an adapter to use
for PouchDB, it will use an IndexedDB or WebSQL adapter,
depending on which browser you use. If you'd like to know
which adapter is used by PouchDB, you can look it up:
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 17/18
var db = new PouchDB('birthdays2'); console.log(db.adapter);
On a mobile device the adapter will be displayed as websql
even if it is using SQLite, so to con¿rm that it is actually
using SQLite you'll have to do this (see answer on
StackOverÀow):
var db = new PouchDB('birthdays2'); db.info().then(console.log.bind(console));
This will output an object with a sqlite_plugin set to true
or false .
Delete database
var db = new PouchDB('birthdays2'); db.destroy().then(function() { console.log('ALL YOUR BASE ARE BELONG TO US'
The source code can be found on GitHub.
I hope this tutorial was helpful to you, leave a comment if
you have any questions. For more information on PouchDB
and NoSQL check out the links below.
Read More
5/30/2016 How To Use PouchDB + SQLite For Local Storage In Ionic 2
http://gonehybrid.com/howtousepouchdbsqliteforlocalstorageinionic2/ 18/18
comments powered by Disqus
Read MoreRed Pill or Blue Pill? Choosing Between SQL & NoSQL
Introduction to PouchDB
E½ciently managing UI state with PouchDB
12 pro tips for better code with PouchDB
PouchDB Blog
Syncing Data with PouchDB and Cloudant in Ionic 2
Follow me on Twitter @ashteya and sign up for myweekly emails to get new tutorials.
If you found this article useful, could you hit the share
buttons so that others can bene¿t from it, too? Thanks!
Ashteya BiharisinghI build hybrid mobile apps or read a good book
when my little boy gives me a break. Now reading:
The Art Of Learning by Josh Waitzkin.
Cork, Ireland
Share this post
Gone Hybrid © 2016 | Powered by Digital Ocean - GET $10CREDIT