npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

angular-pouchdb

v5.0.2

Published

AngularJS wrapper for PouchDB

Downloads

1,861

Readme

angular-pouchdb

Build Status Coverage Status

AngularJS v1.x wrapper for PouchDB

A lightweight AngularJS (v1.x) service for PouchDB that:

  • Wraps Pouch's methods with $q
  • Makes Angular aware of asynchronous updates

Disclaimer: angular-pouchdb works by monkey patching PouchDB's public API. Your milage may vary.

Why?

Since PouchDB is asynchronous, you will often need to call $scope.$apply() before changes are reflected on the UI. For example:

angular.controller('MyCtrl', function($scope, $window) {
  var db = $window.PouchDB('db');
  db.get('id')
    .then(function(res) {
      // Binding may/may not be updated depending on whether a digest cycle has
      // been triggered elsewhere as Angular is unaware that `get` has resolved.
      $scope.one = res;
    });

  var db2 = $window.PouchDB('db2');
  db.get('id')
    .then(function(res) {
      $scope.$apply(function() {
        // Value has been bound within Angular's context, so a digest will be
        // triggered and the DOM updated
        $scope.two = res;
      });
    });
});

Writing $scope.$apply each time is laborious and we haven't even mentioned exception handling or $digest already in progress errors.

angular-pouchdb handles $scope.$apply for you by wrapping PouchDB's promises with $q. You can then use its promises as you would with any Angular promise, including the .finally method (not in the Promises A+ spec).

angular.controller('MyCtrl', function($scope, pouchDB) {
  var db = pouchDB('db');
  db.get('id')
    .then(function(res) {
      // Update UI (almost) instantly
      $scope.one = res;
    })
    .catch(function(err) {
      $scope.err = err;
    })
    .finally(function() {
      $scope.got = true;
    });
});

Put another way, angular-pouchdb is not required to integrate PouchDB and AngularJS; they can and do happily work together without it. However, angular-pouchdb makes it more convenient to do so.

Usage

  1. Install angular-pouchdb via Bower:

    bower install --save angular-pouchdb
  2. Add pouchdb as a module dependency:

    angular.module('app', ['pouchdb']);
  3. Inject the pouchDB service in your app:

    angular.service('service', function(pouchDB) {
      var db = pouchDB('name');
    });

From then on, PouchDB's standard promises API applies. For example:

angular.controller('MainCtrl', function($log, $scope, pouchDB) {
  var db = pouchDB('dbname');
  var doc = { name: 'David' };

  function error(err) {
    $log.error(err);
  }

  function get(res) {
    if (!res.ok) {
      return error(res);
    }
    return db.get(res.id);
  }

  function bind(res) {
    $scope.doc = res;
  }

  db.post(doc)
    .then(get)
    .then(bind)
    .catch(error);
});

See examples for further usage examples.

Event emitters

angular-pouchdb decorates PouchDB event emitters (such as those used by replicate.{to,from}) with a .$promise property to make them more useful within Angular apps, per the following mapping:

Event | Deferred method ----- | ------------------- change | .notify paused | .notify complete | .resolve reject | .reject

For example:

var db = pouchDB('test');
db.replicate.to('https://couch.example.com/remote').$promise
  .then(null, null, function(progress) {
    console.log('replication status', progress);
  })
  .then(function(result) {
    console.log('replication resolved with', result);
  })
  .catch(function(reason) {
    console.error('replication failed with', reason);
  })
  .finally(function() {
    console.log('done');
  });

Options

pouchDBProvider.methods

A hash of pouchDBMethod: decorator pairs, with arbitrary nesting. Defaults to POUCHDB_METHODS (a constant mapping PouchDB's core API).

Example:

pouchDBProvider.methods = {
  get: 'qify',
  replicate: 'replicate'
};

pouchDBDecorators

A service containing decorator functions used to wrap PouchDB's. By default, this includes qify, eventEmitter and replicate.

Since they're contained in a service, they can be substituted per standard dependency injection semantics, or reused outside of angular-pouchdb.

FAQ

Does this work with PouchDB plugins?

angular-pouchdb only wraps PouchDB's core API by default. If you need to wrap other methods (for example, one exposed by a PouchDB plugin), there are (at least) two strategies:

If the method exists synchronously, add the method name to pouchDBProvider.methods in an angular.config block, for example:

.config(function(pouchDBProvider, POUCHDB_METHODS) {
  // Example for nolanlawson/pouchdb-authentication
  var authMethods = {
    login: 'qify',
    logout: 'qify',
    getUser: 'qify'
  };
  pouchDBProvider.methods = angular.extend({}, POUCHDB_METHODS, authMethods);
})

If the method is added after instantiation asynchronously (perhaps via a promise), manually apply a decorator to the instance, for example:

.controller('myCtrl', function(pouchDB, pouchDBDecorators) {
  // Example for nolanlawson/pouchdb-find
  var db = pouchDB('db');
  db.find = pouchDBDecorators.qify(db.find);
});

How can I debug this?

Debugging angular-pouchdb in a console can be done by first retrieving the injector and calling the pouchDB service as normal, e.g.:

var pouchDB = angular.element(document.body).injector().get('pouchDB');
var db = pouchDB('mydb');
db.get('id').then();

For further tips and tricks, see CouchDB Best Practices.

Can this be used with Browserify?

Yes! For example:

require('angular').module('app', [
  require('angular-pouchdb')
]);

Can this be used with webpack?

Yes, though you need to use expose-loader to ensure PouchDB is available as a global, for example:

require('expose?PouchDB!pouchdb');

Why do promises timeout in my test suite?

Note: some (or all) parts of this section may be incorrect or misleading. Your input is welcome.

In short, AngularJS uses a different task scheduler than native promises.

Promises can be implemented differently. PouchDB uses native (A+-compliant) promises (or lie in environments without native support). Native promises are scheduled using "the microtask queue". AngularJS uses its own promise implementation; $q, which are scheduled via $evalAsync.

During normal use, PouchDB's (wrapped) promise is resolved correctly. However during testing, suites that use ngMock (angular-mocks) often unexpectedly timeout.

Typically, $rootScope.$apply() is used to propagate promise resolution in asynchronous tests. This triggers a digest cycle, which in turn flushes Angular's asyncQueue. Whilst this resolves $q promises, it does not resolve PouchDB's native promises, hence causing the test runner (e.g. Karma) to timeout.

Until Angular's promise implementation is decoupled from its digest cycle and/or Angular-specific implementations can be swapped out with their native equivalents, there are a few known workarounds:

Do not use ngMock

ngMock modifies Angular's deferred implementation in order to support writing tests in a synchronous manner. Arguably, this simplifies control flow, but comes at the cost of making $q-wrapped promises difficult to test.

One workaround (and the one that angular-pouchdb currently uses) is to not use ngMock and manually handle $injector, for example:

describe('Working $q.when tests', function() {
  var pouchdb;
  beforeEach(function() {
    // Note, `ngMock` would usually inject `ng` for us
    var $injector = angular.injector(['ng', 'test']);
    var pouchDB = $injector.get('pouchdb');
    pouchdb = pouchDB('db');
  });

  it('should resolve a promise', function(done) {
    pouchdb.info()
      .then(function(info) {
        expect(info).toBeDefined();
      })
      .finally(done);
  });
});

This preserves "normal" promise resolution behaviour, but will not suit all scenarios, such as when you need the additional introspection/async control features ngMock provides e.g. $httpBackend.flush.

Spam $rootScope.$apply

Calling $rootScope.$apply in quick succession to cause a near-continuous digest cycle forces promise resolution. This appears to be due to tight coupling between Angular's promises and its digest cycle.

it('should wrap destroy', function(done) {
  // Note, you might want to experiement with a interval timeout here
  var interval = $window.setInterval($rootScope.$apply.bind());
  db.destroy()
    .then(shouldBeOK)
    .then($window.clearInterval.bind(null, interval))
    .catch(shouldNotBeCalled)
    .finally(done);
})

Note, this is likely to significantly decrease your test's performance.

Does this work with Angular v2?

No and it doesn't need to! Angular v2's concept of change detection completely differs to Angular v1's; the digest cycle, $scope.$apply and friends are no more. Just use PouchDB directly.

Authors

License

Released under the MIT License.