Git Product home page Git Product logo

localforage-observable's Introduction

localForage-observable

Build Status npm
Adds observables to localForage, providing a way to get notified whenever:

  • a method that affects the database is invoked
  • the value associated with a specific key changes

Requirements

Usage

Currently localForage Observables should only be created after localforage.ready(), so that localForage completes the initialization of the requested (or best matching) driver. Moreover, Observables will stop working in case you change the driver in use, after their creation.

Observe for changes with newObservable()

Creates an observable and subscribes to DB changes. With this method Subscribers get notified with a LocalForageObservableChange object. This method can be invoked with a LocalForageObservableOptions object as optional argument.

Observe everything

var observable = localforage.newObservable();
var subscription = observable.subscribe({
  next: function(args) {
    console.log('I observe everything', args);
  },
  error: function(err) {
    console.log('Found an error!', err);
  },
  complete: function() {
    console.log('Observable destroyed!');
  }
});

Observe a specific key

var observable = localforage.newObservable({
    key: 'testKey'
});
var subscription = observable.subscribe({
  next: function(args) {
    console.log('testKey has changed to:', args.newValue);
  }
});

Observe specific method calls

var observable = localforage.newObservable({
    // setItem: false,
    removeItem: true,
    clear: true
});
var subscription = observable.subscribe({
  next: function(args) {
    console.log(args.methodName + ' was called!');
  }
});

Get a "live" Observable of a DB Item Value with getItemObservable(key)

Creates an observable for a specific key that returns the current DB value and every new saved value. With this method Subscribers receive the initial and ongoing DB values for a specific key as it changes. This method can be invoked with a LocalForageObservableOptions object as extra optional argument.

var useProfileObservable = localforage.getItemObservable('UserProfile');
useProfileSubscription = useProfileObservable.subscribe({
  next: function(value) {
    setCurrentUserNameToPage(value.username);
  }
});

Cancel an Observable Subscription

subscription.unsubscribe();

Value change detection

Deep value change detection is enabled by default. This way our Observable Subscribers get notified only when the value of the associated key actually changes. Obviously, deep equality checking adds some extra overhead, so in case that all you need is to get notified on any attempt to change a value, you can easily disable value checking:

var observable = localforage.newObservable({
    key: 'testKey',
    changeDetection: false
});

Cross-Tab Observables #5

Cross-tab event emission, observation and value change detection are disabled by default.

In order to enable it, you have to:

  1. call the configObservables() method to start emmiting cross-tab events:
localforage.configObservables({
  crossTabNotification: true
});
  1. create observables with cross-tab observation enabled:
var observable = localforage.newObservable({
  crossTabNotification: true,
  changeDetection: false
});

The arguments passed to cross-tab observable callbacks, will also have the crossTabNotification property set.

Cross-tab change detection

Cross-tab observation with change detection is also supported, but with some limitations. The arguments passed to the callback will have the valueChange property set to true but:

  • the oldValue will always be null and
  • the newValue will hold the value retrieved from the local db at the time that the notification arrived. In that case you can use:
localforage.configObservables({
  crossTabNotification: true,
  crossTabChangeDetection: true
});
var observable = localforage.newObservable({
  crossTabNotification: true
});

API

interface LocalForageObservableOptions {
    key: string;
    setItem: boolean;
    removeItem: boolean;
    clear: boolean;
    changeDetection?: boolean; // default true
}

interface LocalForageObservableChange {
    key: string;
    methodName: string;
    oldValue: any;
    newValue: any;
    valueChange?: boolean;
    success?: boolean;
    fail?: boolean;
    error: any;
    crossTabNotification?: string;
}

Using a different Observable library

You can actually use any library compatible with the ES Observable spec proposal. For example, in order to make localForage-observable use the Observables of the RxJS, all you have to do is change the provided Observable Factory method:

localforage.newObservable.factory = function (subscribeFn) {
    return Rx.Observable.create(subscribeFn);
};

TypeScript

First of all, include localforage with an import statement appropriate for your configuration and import localforage-observable right after it.

Normally, localforage-observable will extend the prototype of locaforage to include newObservable() etc, but unfortunately the typings can't be updated. As a result you should use the exported extendPrototype() method, which returns the provided localforage instance but with inherited typings that also include the extra methods of localforage-observable.

import localForage from "localforage";
// OR based on your configuration:
// import * as localForage from "localforage";

import { extendPrototype } from "localforage-observable";

var localforage = extendPrototype(localForage);
localforage.ready().then(() => {
  // TypeScript will find `newObservable()` after the casting that `extendPrototype()` does
  var observable = localforage.newObservable();
});

Examples

localforage-observable's People

Contributors

danmaas avatar neelabhg avatar thgreasi avatar tofumatt avatar waynebrantley avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

localforage-observable's Issues

[Question] Observe this same store from different instances

Hi, there is a way to observe this same store and detect "cross" changes from two different instances? I was able to only detect changes made from this same instance.

const instanceOne = localforage.createInstance({
    name        : dbName,
    storeName   : 'tableOne',
});

const instanceTwo = localforage.createInstance({
    name        : dbName,
    storeName   : 'tableOne',
});

...

const observableOne = instanceOne.newObservable()
const subscriptionOne = observableOne.subscribe({ next: (args) => { ... } })

...

const observableTwo = instanceTwo.newObservable()
const subscriptionTwo = observableTwo.subscribe({ next: (args) => { ... } })

...
 
instanceOne.setItem("ACTION", { value: "something" }) // it should be caught by both observable
 

ReferenceError: Observable is not defined

Hi,

I've installed this library's v1.4.0 and I'm getting this error ("ReferenceError: Observable is not defined"). I've tried to use it like this:

import * as localforage from "localforage";
import "localforage-observable";

[...]

  componentDidMount = () => {
    localforage.ready(() => {
      const observable = localforage.newObservable({ key: "Messages" });
      this.subscription = observable.subscribe({
        next: data => {
          // handle data changes
        }
      });
    });
  };

But I always get the error and I don't know which could be the error.

I've checked the examples (https://codepen.io/thgreasi/pen/LNKZxQ) and the error appears too.

Thanks!

localforage.setItem in a promise won't fire Observable with rxjs

So I have this method which pulls user data from the server and then caches it via localforage. When I set the data in a promise the Observable isn't fired.

UserCacheProxy

public getUsers(userIds: string[], callback: NextObserver<any> | Function) {
    let cacheKeys = userIds.map((userId:any) => {
        return this.getUserCacheKey(userId);
    });

    let applyCallback = (item) => {
        this.$rootScope.$apply(() => {
            callback(item);
        });
    };

    //noinspection TypeScriptUnresolvedFunction
    let subscriber = Observable.from(cacheKeys)
        .flatMap((key) => {
            this.CacheService.getItem(key)
                .then((user: IApiUser) => {
                    return new ngLeague.User(user);
                })
                .then(applyCallback)
                .catch(x => x);

            return this.CacheService.getObservable(key);
        })
        .map((user:IApiUser) => {
            console.log(user);
            return new ngLeague.User(user);
        })
        .subscribe(applyCallback);

    this.CacheService.setItem("user:9373305", "Hi", this.CachingTimes.getUserCacheTimeout());

    this.fetchUncachedUsers(userIds).then((users) => {
        this.CacheService.setItem("user:9373305", "Hi2", this.CachingTimes.getUserCacheTimeout());

        _.forEach(users, (user: IApiUser) => {
            let cacheKey = this.getUserCacheKey(user.id);
            this.CacheService.setItem(cacheKey, user);
        });
    });

    return subscriber;
}

Which I call like that:

UserCacheProxy.getUsers(["9373305"], function(user:ngLeague.User) {
    // do nothing
});

Expected result:

User {apiData: "Hi"}
User {apiData: "Hi2"}
User {apiData: "{..}"} // actual user data from the server

Actual result:

User {apiData: "Hi"}

Note:

  • Also happens without the $rootScope.$apply from angular
  • Doesn't matter if item already exists in the database or not

I'm interested in what this adds to localForage's promise based api?

Really well documented project btw. The API definition in typescript is a nice idea I wish other people would follow.

I'm interested in the value of this project though.

Is it just converting a localforage promise to a one shot observable?
If so a generic function to convert promise to one shot observables like RxJS Rx.Observable.fromPromise() should be used in a project.

Use LocalForage-observable in an es6/typescript environment

I'd like to use localforage-observable in a typescript project (Angular2). What is the correct way to import and use it using es6 modules? For example, I can use localforage in a module by importing it:

import * as localforage from 'localforage';

Localforage-observable just extends localforage, but I can't figure out how to include it and extend localforage. I've tried each of the following to no avail (including the above statement every time):

import * as lo from 'localforage-observable';
import 'localforage-observable';
require('localforage-observable');
const lo = require('localforage-observable');

None of those work. Can you point me in the right direction?

ReferenceError: Observable is not defined

I have converted my app to use the new corejs as babel/polyfill is deprecated. https://babeljs.io/docs/en/babel-polyfill

When I remove babel-polyfill from my webpack:

        entry: {
            'main-client': [
                "babel-polyfill",
                'react-hot-loader/patch',
                './clientApp/boot-client.tsx'
            ]
        },

It causes Observable is not defined. (and this is on latest version of chrome that does not need any polyfills).
Uncaught (in promise) ReferenceError: Observable is not defined
at Function.newObservable.factory (localforage-observable.js:443)
at LocalForage.newObservable (localforage-observable.js:430)

I put the babel-polyfill back and it works just fine. Any thoughts - I noticed your zen dependency is pretty far behind, but not sure if that will fix it?

Observable is not defined error while trying localForage.newObservable({})

I'm working on [email protected] with [email protected] and localforage-observable@^2.1.1

Just following the same steps as in documentation, but getting error in localforage.newObservable(). Tried with different versions of localforage-observable also, but nothing works

import localForage from "localforage";
// OR based on your configuration:
// import * as localForage from "localforage";

import { extendPrototype } from "localforage-observable";

var localforage = extendPrototype(localForage);
localforage.ready().then(() => {
  // TypeScript will find `newObservable()` after the casting that `extendPrototype()` does
  var observable = localforage.newObservable();
});

Following error while running application:

Unhandled Promise rejection: Observable is not defined ; Zone: <root> ; Task: Promise.then ; Value: ReferenceError: Observable is not defined
    at newObservable.factory (localforage-observable.js:444:9)
    at LocalForage.newObservable (localforage-observable.js:431:40)

How to merge multiple observables in to one?

I've tried the following

CacheService.ts

public getObservable(key) {
        return this.localForage.newObservable({key: key}).map((item:any) => {
            return this.getItemContent(key, item);
        });
}

Doesn't fire the subscribe methods

return Observable.from(teamIds).flatMap((teamId:any) => {
    return this.CacheService.getObservable(this.getTeamCacheKey(teamId));
});

Doesn't fire the subscribe methods either

let observables = teamIds.map((teamId:any) => {
    return this.CacheService.getObservable(this.getTeamCacheKey(teamId));
});

//noinspection TypeScriptUnresolvedFunction
return Observable.concat(observables).flatMap((x:any) => {
    return x;
});

note: When I use .map instead of .flatMap it works, but it returns the single Observables which I do not want :)

Support for localforage instances

Would you consider adding support for localforage instances?
Are there big problems to solve for it?
Is there a workaround I can use to support it now?

clear() doesn't trigger event

Using the code below, i don't seem to get an event for the localforage.clear() method.

import localforage from 'localforage'
import 'localforage-observable'

let store = localforage.createInstance({name:'clear-test'})
store.ready(function() {
  let observable = store.newObservable({
  })
  observable.subscribe({
    next: function(args) {
      console.log('observable', args);
    }
  })
})

store.setItem('1','test')
.then(()=>{store.clear()})

I do get an event on the setItem() method.
The 'clear-test' database is emtpy afterward, so the clear() method worked.

Tested on FF 58.0.2 and IE 11.248
localforage: 1.5.3 and 1.6.0
localforage-observable: 1.4.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.