Mobile & Offline Data Synchronization in AngularJS
http://bit.ly/zen-ng-pouchdb
Daniel Zen@zendigital
My Background
● Longtime JavaScript programmer● Former XP Consultant for Google & Pivotal ● Started using AngularJS 2 years ago● Started AngularJS-NYC Meetup May 2012● Reformed Zen Digital consultancy 2013
○ Web & mobile application development○ Focus on using latest technologies & solutions
Outline for this talk:
● Requirements for AngularJS data models● Standard Online Techniques
○ CRUD,RESTful APIs○ $http, $resource
● Offline issues● local storage options● Sample Application walk through
○ Ionic○ PouchDb
Requirements for data models in AngularJS:
Requirements for models in AngularJS:
ABSOLUTELY NOTHING● AngularJS is model agnostic● Any variable or object can serve as a model● No unique ID required● No built-in persistence model for objects● ng-model binds javascript variables to UI not
to backend
What does this mean for data persistence
● There is no standard, yet○ See AngularJS 2.0 Data Persistence Design Doc
● Various open source storage options○ SQL
■ MySQL■ PostgreSQL
○ NoSQL■ MongoDB■ CouchDB
Common Persistence Practices
● CRUD - Create, read, update and delete
Each letter in the acronym can map to a standard SQL statement and HTTP method:
Operation` SQL HTTP
Create INSERT PUT / POST
Read (Retrieve) SELECT GET
Update (Modify) UPDATE PUT / PATCH
Delete (Destroy) DELETE DELETE
Typically we employ RESTful APIs
● RESTful APIs - Representational state transferThe name “Representational State Transfer” is intended to evoke an image of how a well-designed Web application behaves: a network of Web pages forms a virtual state machine, allowing a user to progress through the application by selecting a link or submitting a short data-entry form, with each action resulting in a transition to the next state of the application by transferring a representation of that state to the user. - Roy Fielding
● HTTP 1.1 based on REST
Common REST Practices
Resource POSTcreate
GETread
PUTupdate
DELETEdelete
/accounts Create a new account
List accounts Bulk update accounts
Delete all accounts
/accounts/123 Error Show account 123
If exists update account 123
If not error
Delete account 123
/customers Create a new customer
List customers Bulk update customers
Delete all customers
/customers/456 Error Show customer 456
If exists update customer 456
If not error
Delete customer 456
$http Service
● The AngularJS XmlHttpRequest API follows the Promise interface ($q service)○ Returns a promise object with the standard then method
and two http specific methods: success and error. $http({method: 'GET', url: '/someUrl'}). success(function(data, status, headers, config) { // this callback will be called asynchronously // when the response is available }). error(function(data, status, headers, config) { // called asynchronously if an error occurs // or server returns response with an error status. });
$resource - a higher level abstraction
● service in module ngResource● factory lets you interact with server-side data● returns resource with methods for CRUD
operations: get, save, query, remove, delete● operations can be invoked by the following:● no need to interact with the low level $http
● HTTP GET "class" actions: Resource.action([parameters], [success], [error])● non-GET "class" actions: Resource.action([parameters], postData, [success], [error])● non-GET instance actions: instance.$action([parameters], [success], [error])
$resource - a higher level abstraction
● You can also access the raw $http promise via the $promise property on the object returned
● More reference: Angular communication $http & $resource
var User = $resource('/users/:userId', {userId:'@id'}); User.get({userId:123}) .$promise.then(function(user) { $scope.user = user; })
But what about offline?
● Web apps no longer dependent on servers● Solution: richer clients (using AngularJS ;)● Google Docs is a good example● For offline first experience:
○ You need to store the data in the front end○ You need it to sync to the server’s data store.
● In browser databases available:○ derby.js, Lawnchair, Sench touch
● requirement: online synchronization
What have we come to expect
● Email should work offline○ Local copy of recent emails○ Can read or delete○ Can write new emails, and will send when online
● Google Docs keeps pushing threshold○ In Chrome we can view and edit while offline○ mobile version now has offline edit capability
● Conflict resolution○ Intelligently merge documents with multiple edits
Connectivity Lifecycle
Failures can happen on: client push, or client pull/ server push
● Communicate or hide connectivity state○ Chat app
● Enable client-side creation and editing features○ Todo app
● Disable, modify, or hide features that won’t work○ Facebook status, Twitter Tweets
● Notify user about possibly conflicting data● Conflict resolution tools (merge)
How to deal with being offline
● “You are offline”○ “Unable to connect to the Internet”○ We need to stop treating offline as an error condition
● Try not to block features completely○ If you can’t update, show old data (with message)○ Let user create data locally to be sent later
● Dealing with new incoming data. Options:○ Show it as the most recent○ Show it in chronological order
So what are local storage storage?
● Roll your own!○ Use localstorage, indexDb, or WebSql directly
● Open source local storage databases that sync○ PouchDB (JavaScript database that syncs!)○ Hoodie (Another JS db that syncs. In preview mode)○ remotestorage.io (IETF Proposed Standard)
● Proprietary solution?○ Firebase (AngularFire)
■ Firebase transparently reconnects to server■ But doesn’t persist to local storage
Firebase
● Pros○ AngularJS library (AngularFire)○ 3-way binding with $bind○ Free Developer (Hacker) plan○ Paid solution with premium support○ Hosted solution○ Can deploy static hosted apps
● Cons○ Proprietary solution○ Hosted solution (can’t run local or on own servers)○ No local storage solution
PouchDB
● Pros:○ Open Source ○ Lightweight Cross Browser JavaScript implementation○ Syncs with open source CouchDB protocol servers
■ PouchDB-Server - a HTTP on top of PouchDB■ Cloudant - A cluster aware fork of CouchDB■ Couchbase Sync Gateway
● Cons:○ No Standard AngularJS library (yet)
■ angular-pouchdb looks promising
Sample Application: ionic-pouchdb-todo
● Source code will be available at:○ http://github.com/danielzen/ionic-pouchdb-todo (soon)
● Uses ionic hybrid mobile app framework● Pre-requisites:
○ Node○ CouchDb
Resources
● Data Persistence in Angular 2.0
● Designing Offline - Alex Feyerke
● Building offline applications with AngularJS and PouchDB
● Sync multiple AngularJS apps without server via PouchDB
● TodoMVC (AngularJS) + Hood.ie = 60 minutes to awesome
A copy of these slides is available at:
http://bit.ly/zen-ng-pouchdb