Offline/Online Sync in a Real World Ionic Application with CouchDB
This is supposed to be a longer description
Getting Data From CouchDB into Ionic
Pulling data into Ionic, and pushing data back to CouchDB
PROModule Outline
- Source Code & Resources PRO
- Lesson 1: Introduction PUBLIC
- Lesson 2: Application Requirements PUBLIC
- Lesson 3: A Brief Introduction to NoSQL PUBLIC
- Lesson 4: Introduction to CouchDB PRO
- Lesson 5: Introduction to PouchDB PRO
- Lesson 6: Structuring Data in CouchDB PRO
- Lesson 7: Installing CouchDB Locally PRO
- Lesson 8: Adding Data to Futon PRO
- Lesson 9: Starting the Application PRO
- Lesson 10: Setting up the Basic User Interface PRO
- Lesson 11: Using Design Documents to Create Views in CouchDB PRO
- Lesson 12: Getting Data From CouchDB into Ionic PRO
- Lesson 13: Using Node, Express, and SuperLogin PRO
- Lesson 14: Login and Registration PRO
- Lesson 15: Offline Access and Reauthentication PRO
- Lesson 16: Advanced Form Validation PRO
- Lesson 17: Restricting Document Updates PRO
- Lesson 18: Filtering Data from CouchDB PRO
- Lesson 19: Improving User Experience PRO
- Lesson 20: Migrating to Production PRO
- Lesson 21: Conclusion PRO
Lesson Outline
Getting Data From CouchDB into Ionic
We've built a little bit of our application, and we've set up a little bit of our database, but up until this point, they have both existed entirely separately from each other. In this lesson, we are going to bring those two worlds together by doing the following:
- Set up PouchDB and get it talking with our CouchDB database
- Set up the Notices and Chats services so that we can retrieve and store data
- Update the user interface to make use of the services
At the end of this lesson, we should be able to display real data in our application, and also create our own new notices and chats through the application.
Create the Design Documents
Before we start pulling data into our application, we are going to set up the views we need in our CouchDB database. As we discussed in the last lesson, we can create a view inside of a design document in CouchDB to create a list of specific data based on a map function.
Our views are going to be very simple. We want to be able to pull in a list of notices into our notices page, and we want to be able to pull in a list of chats into our chats page, so we will create two separate views to achieve this. One view will list all of the notices, and another view will list all of the chats.
We are going to create two separate design documents to do this, one for chats and one for notices. This is not necessary, we could just create a single 'app' design document that implemented both of the views, but creating separate design documents helps to keep things organised. We will also be adding other features to the design documents later, so it is going to be cleaner to keep things separated. But I do want to emphasise the fact that it doesn't matter if we have a "notices" design document and a "chats" design document, the views in these design documents will still run on all documents in the database (both chats and notices).
Add the following document to your CouchDB database (you can just create this as a normal document like any other, you don't need to create it anywhere specific):
{
"_id": "_design/notices",
"language": "javascript",
"views": {
"by_date_updated": {
"map": "function(doc){ if(doc.type === 'notice'){emit(doc.dateUpdated);} }"
}
}
}
This is our notices
design document, and we have created a by_date_updated
view. We already discussed the purpose of this in the last lesson, but to quickly recap: this map function will create a view that contains all of the notices in the database, and it will use the dateUpdated
field as the key. This will allow us to sort the notice documents by the date they were last updated.
NOTE: Be careful using quotation marks when adding functions to design documents. In the example above we use single quotes for 'notice'
but if you use double quotes you need to make sure to escape it with a slash \"
so that it doesn't break the string used as the map function.
Add the following document to your CouchDB database:
{
"_id": "_design/chats",
"language": "javascript",
"views": {
"by_date_created": {
"map": "function(doc){ if(doc.type === 'chat'){emit(doc.dateCreated);} }"
}
}
}
This is the design document for chats
and it is almost exactly the same as the notices
design document, except that we use the dateCreated
field as the key. It will not be possible to update chats once they are created, so we don't have a dateUpdated
field.
Implement the Data Service
We've done everything that needs to be done on CouchDB's end to start pulling data into our application, so let's implement the Data provider now. As I mentioned earlier, we want the Data provider to handle most of the integration with PouchDB and CouchDB so that we can abstract the implementation details away from the rest of our application as much as possible. The data provider will be the middleman between our application and the database.
Let's create the data provider now.
Modify src/app/services/data.service.ts to reflect the following:
import { Injectable } from '@angular/core';
import PouchDB from 'pouchdb-browser';
@Injectable({
providedIn: 'root',
})
export class DataService {
public db: PouchDB.Database = null;
private remote: string;
constructor() {}
initDatabase(remote: string): void {
this.db = new PouchDB('hangz-app', {
auto_compaction: true,
});
this.remote = remote;
this.initRemoteSync();
}
initRemoteSync(): void {
let options = {
live: true,
retry: true,
};
this.db.sync(this.remote, options);
}
createDoc(doc: any): Promise<any> {
return this.db.post(doc);
}
updateDoc(doc: any): Promise<any> {
return this.db.put(doc);
}
deleteDoc(doc: any): Promise<any> {
return this.db.remove(doc);
}
}
We make PouchDB's functionality available in this class by importing it:
import PouchDB from 'pouchdb-browser';
We use that to create a new local PouchDB database called hangz-app
, with the auto_compaction
option set to true
(this basically helps keeps our database tidy over time by removing old revisions). If the database does not already exist locally it will create it, but if it does already exist then it will just use that existing database.
This is triggered within an initDatabase
method that we will call at some point during the startup of the application, and we will pass in the URL for the remote
CouchDB database into it. We then use that URL in the initRemoteSync
method, which sets up the live sync between the local PouchDB database and the remote CouchDB database.
In the options for the sync, we set both live
and retry
to true. The live
option will subscribe to changes so that when there are any changes they will automatically be replicated. The retry
option will make PouchDB reattempt replication if a failure occurs. This is especially important for getting this to work in the case of a user being offline and then coming back online - the initial replication would fail whilst they are offline, but once they come online the connection to the remote database can be established.
We have also created three methods for creating, updating, and deleting documents. We will be able to pass in documents to these methods, and then the data provider will handle performing the operations.
There's a subtle difference between posting
and putting
a document, you may notice that for creating documents we use post
but for updating documents we use put
. You should use put
in cases where you know the _id
of a document, i.e. cases where you are updating an existing document, or when you are creating a new document but you want to specify the _id
yourself. If you are creating a new document and not supplying an _id
, you should use post
.
Thanks for checking out the preview of this lesson!
You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).