Skip to content

Commit

Permalink
Fixes #78 adds new syncCondition config option
Browse files Browse the repository at this point in the history
  • Loading branch information
bufke committed Jan 30, 2018
1 parent e036adf commit 714f1b3
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -76,6 +76,7 @@ An interface defining the configuration attributes to bootstrap `localStorageSyn
* `removeOnUndefined` (optional) `boolean`: Specify if the state is removed from the storage when the new value is undefined, this will default to `false`.
* `storageKeySerializer` (optional) `(key: string) => string`: Сustom serialize function for storage keys, used to avoid Storage conflicts.
* `restoreDates` \(*boolean? = true*): Restore serialized date objects. If you work directly with ISO date strings, set this option to `false`.
* `syncCondition` (optional) `(state) => boolean`: When set, sync to storage medium will only occur when this function returns a true boolean. Example: `(state) => state.config.syncToStorage` will check the state tree under config.syncToStorage and if true, it will sync to the storage. If undefined or false it will not sync to storage. Often useful for "remember me" options in login.
Usage: `localStorageSync({keys: ['todos', 'visibilityFilter'], storageKeySerializer: (key) => 'cool_' + key, ... })`. In this example `Storage` will use keys `cool_todos` and `cool_visibilityFilter` keys to store `todos` and `visibilityFilter` slices of state). The key itself is used by default - `(key) => key`.

---
Expand Down
42 changes: 42 additions & 0 deletions spec/index_spec.ts
Expand Up @@ -374,4 +374,46 @@ describe('ngrxLocalStorage', () => {
expect(t1 instanceof TypeA).toBeTruthy();
expect(finalState.simple instanceof TypeA).toBeFalsy();
});

it('syncCondition', () => {
// Test that syncCondition can selectively trigger a sync state update
let s = new MockStorage();
let skr = mockStorageKeySerializer;

// Selector always returns false - meaning it should never sync
const shouldNotSyncSelector = (state: any) => {
return false;
};

syncStateUpdate(initialState, ['state'], s, skr, false, shouldNotSyncSelector);

let raw = s.getItem('state');
expect(raw).toEqual(null);

let finalState: any = rehydrateApplicationState(['state'], s, skr, true);
expect(JSON.stringify(finalState)).toEqual('{}');

// Selector should error - so still no sync
const errorSelector = (state: any) => {
return state.doesNotExist;
};

syncStateUpdate(initialState, ['state'], s, skr, false, errorSelector);

raw = s.getItem('state');
expect(raw).toEqual(null);

// Selector always returns true - so it should sync
const shouldSyncSelector = (state: any) => {
return true;
};

syncStateUpdate(initialState, ['state'], s, skr, false, shouldSyncSelector);

raw = s.getItem('state');
expect(raw).toEqual(t1Json);

finalState = rehydrateApplicationState(['state'], s, skr, true);
expect(JSON.stringify(finalState)).toEqual(initialStateJson);
});
});
20 changes: 18 additions & 2 deletions src/index.ts
Expand Up @@ -108,8 +108,22 @@ export const syncStateUpdate = (
keys: any[],
storage: Storage,
storageKeySerializer: (key: string) => string,
removeOnUndefined: boolean
removeOnUndefined: boolean,
syncCondition?: (state: any) => any
) => {
if (syncCondition) {
try {
if (syncCondition(state) !== true) {
return;
}
} catch (e) {
// Treat TypeError as do not sync
if (e instanceof TypeError) {
return;
}
throw e;
}
}
keys.forEach(key => {
let stateSlice = state[key];
let replacer = undefined;
Expand Down Expand Up @@ -236,7 +250,8 @@ export const localStorageSync = (config: LocalStorageConfig) => (
stateKeys,
config.storage,
config.storageKeySerializer,
config.removeOnUndefined
config.removeOnUndefined,
config.syncCondition
);
return nextState;
};
Expand Down Expand Up @@ -271,4 +286,5 @@ export interface LocalStorageConfig {
removeOnUndefined?: boolean;
restoreDates?: boolean;
storageKeySerializer?: (key: string) => string;
syncCondition?: (state: any) => any;
}

0 comments on commit 714f1b3

Please sign in to comment.