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

ngx-rxcache

v3.0.3

Published

RxCache is a light weight RxJs Behavior Subject based cache. It offers simple to grasp ways of achieving push based data flow to your components with hardly any boiler plate code at all.

Downloads

319

Readme

RxCache

RxCache is a light weight RxJs Behavior Subject based cache. It offers simple to grasp ways of achieving push based data flow to your components with hardly any boiler plate code at all.

Testbed on StackBlitz

A simple user management example with RxCache

A redo of the official ngrx example app can be seen here on StackBlitz

Usage

npm install --save ngx-rxcache

Inject the service into your service.

import { Injectable } from '@angular/core';
import { RxCacheService, RxCacheItem } from 'ngx-rxcache';

@Injectable()
export class YourService {
  constructor(public cache: RxCacheService) {
    this.item = cache.get<YourType>({ id: 'key', construct: functionThatReturnsObservableOfYourType });
    // or
    this.item = cache.get<YourType>({ id: 'key', initialValue : instanceOfYourType });
  }

  item: RxCacheItem<any>;

  data$ = this.item.value$;

  update = (value) => { this.item.update(value); };
}

The cache has methods for configuring, retrieving, checking for the existence of and deleting items. It also has methods for setting the global error message and handler.

A cache item is a simple light weight object that consists of an instance behaviour subject and optional behaviour subjects to signify the loading, loaded, saving, saved, and error states the item may be in.

const item = cache.get('key');

Will retrieve an existing item from the cache or create a new one if one is not found.

const exists = cache.exists('key');

Returns a boolean the check if an item with that key exists in the cache.

cache.delete('key');

Will delete the item from the cache, complete all behaviour subjects and unsubscribe from the construct function.

cache.genericError('An error has occoured');

Will set the global generic error message

cache.errorHandler((key, error) => {
  logger.log(`Item with key '${key}' caused the error the error: ${error}`);
});

Will set the global generic error handler. If the error handler return a string it will be used as the error message for the error$ behaviour subject.

The get method can take in an object with the interface

export interface RxCacheItemConfig<T> {
  id: string; // A unique string that is used to identify and retrive the item from the cache
  construct?: () => Observable<T>; // An optional constructor function that returns an observable of your type
  save?: (val: T) => Observable<any>; // An optional save function that saves the current instance
  saved?: (val: any) => void; // An optional save callback function that is called after the save method succeeds
  stringify?: (val: T) => any; // An optional function to transform the value before it is stringified for storage
  parse?: (val: any) => T; // An optional function to transform the value after it is parse from storage
  load?: boolean; // An optional flag to call the constructor function as soon as the item is created
  autoload?: boolean; // An optional flag to call the constructor function when the value$ accessor property is called if it is not already loaded
  localStorage?: boolean; // A optional flag to persist the value in localStorage to survive across browser sessions
  sessionStorage?: boolean; // An optional flag to persist the value in sessionStorage to survive browser refresh
  initialValue?: T; // An optional initial value for the item
  genericError?: string; // An optional generic error message to be returned on persist and construct failures
  errorHandler?: (id: string, error?: any) => string; // An error handler to be run on persist and construct failures, if it returns a string it will be used as the error message
}
cache.get({ id: 'key' });

Will return a cache item that only has the instance behaviour subject initialised with it's value set to undefined.

cache.get({ id: 'key', initialValue: 'Hello' });

Will return a cache item that only has the instance behaviour subject initialised with it's value set to a string 'Hello'.

cache.get({ id: 'key', construct: () => of('Hello').pipe(delay(1000)) });

Will return a cache item that only has the instance behaviour subject initialised with it's value set to undefined. Once the load method is called the construct function will be called and the loading$ and loaded$ behaviour subjects will be initiased with true and false respectively. After the one second delay the instance behavior subject will be set to 'Hello', loading will be false and loaded will be true.

cache.get({ id: 'key', construct: () => of('Hello').pipe(delay(1000)), load: true });

Will call the load function as the object is created. For the first second, instance is undefined, loading$ is true and loaded$ is false. Once the construct function is finished the instance is 'Hello', loading$ is false and loaded$ is true.

cache.get({ id: 'key', construct: () => of('Hello').pipe(delay(1000)), autoload: true });

Will cause the load function to be called when the instance behaviour subject's accessor property value$ is acceessed if the item has not been loaded.

cache.get({ id: 'key', construct: () => throwError('An error occoured')), load: true });

Will cause an error when constructing the object, the instance behaviour subject will be undefined, loading$ will be false, loaded$ will be false, hasError$ will be true and error$ will be 'An error has occoured', the global eneric error message.

cache.get({ id: 'key', genericError: 'Oops', construct: () => throwError('An error occoured')), load: true });

Will cause an error when constructing the object, error$ will be 'Oops'.

cache.get({ id: 'key', construct: () => throwError('An error occoured')), load: true, errorHandler: (id: string, error: any) => `Item with id '${id}' failed with the error: ${error}` });

Will cause an error when constructing the object, error$ will be "Item with id 'key' failed with the error: An error occoured".

Persistence to localStorage and sessionStorage

cache.get({ id: 'key', localStorage: true });

Will store the value in localStorage on every update so the value can survive between browser sessions

cache.get({ id: 'key', sessionStorage: true });

Will store the value in sessionStorage on every update so the value can survive browser refresh

Some values such as dates do not persist well in sessionStorage and localStorage as they are turned into a string when JSON.stringify is used to turn the value into string for storage. There are two transformation functions that can be used to transform objects before being stringified and after being parsed.

cache.get({
  id: 'key',
  stringify: (val) => ({ ...val, date: val.date.getTime() }),
  parse: (val) => ({ ...val, date: new Date(JSON.parse(val.date)) })
});

Will transform the value's date property into number of milliseconds before it is stringified for storage and transform the date property back to a date object after it is parsed from storage.

Using a parse function can cause unexpected behaviour if cache.get('key') is used before cache.get({id: 'key', parse: parseFunction }). When cache.get is called with a string for the key instead of a config object it will create one if it is not found. The constructor of the cache item object will instanciate with the value in local or session storage if the key matches a key in local or session storage. If then later cache.get is called with a config object that has a parse function the item will already have a value and the parse function will not run on value that was retrived from storage. This is the only case where the order of calling get with a string or config object matters. If you are using storage transformation functions you must make sure the cache.get(configObject) happens before cache.get(key) to gaurantee the stored value is parsed by the parse function.