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

ngrx-undo-reducer

v2.0.0

Published

Undoable reducer for @ngrx/store

Downloads

99

Readme

ngrx-undo-reducer

npm GitHub license

Heavily inspired by redux-undo

See Demo

Installation

# NPM
npm install ngrx-undo-reducer

# Yarn
yarn add ngrx-undo-reducer

API

AOT Builds (--prod)

Need to use InjectionToken to support AOT builds due to Function call of undoable().

Without it, angular-cli will throw the following error: Function calls are not supported in decorators but 'undoable' was called.

import { undoable } from 'ngrx-undo-reducer';

const config: UndoableOptions<MyState> = { ... }
const reducers: ActionReducerMap<MyState> = {
	stateProp: undoable(fromStateProp.reducer, config),
};
export const reducersToken = new InjectionToken<ActionReducerMap<MyState>>(
	'MyState Reducers', 
	{ factory: () => reducers }
);
@NgModule({
	imports: [
		StoreModule.forRoot(reducersToken)
		// ...
	]
	// ...
})
export class MyModule {}

For non-AOT builds

You can import reducers as you normally would.

import { undoable } from 'ngrx-undo-reducer';

const config: UndoableOptions<MyState> = { ... }
export const reducers: ActionReducerMap<MyState> = {
	stateProp: undoable(fromStateProp.reducer, config),
};
@NgModule({
	imports: [
		StoreModule.forRoot(reducers)
		// ...
	]
	// ...
})
export class MyModule {}

History API

Wrapping your reducer with undoable makes the state look like this:

{
    past: [...pastStatesHere...],
    present: {...currentStateHere...},
    future: [...futureStatesHere...],
    bookmark: {...bookmarkedStateHere...}
}

Configuration

A configuration object can be passed to undoable() like this (values shown are default values):

undoable(reducer, {
	limit: undefined, // set to a number to turn on a limit for the history
	filter: () => true, // see `Filtering Actions`
	undoType: ActionTypes.Undo, // define a custom action type for this undo action
	redoType: ActionTypes.Redo, // define a custom action type for this redo action
	clearHistoryTypes: [ActionTypes.ClearHistory], // define several action types that would clear the history
	bookmarkType: ActionTypes.Bookmark, // define action type that would bookmark the state passed via action.payload or will take state.present if no payload was passed.
	revertToBookmarkTypes: [ActionTypes.RevertToBookmark], // define action types that would revert state to the bookmarked state
	initTypes: [ActionTypes.Init], // will revert to initialState
	debug: false, // set to `true` to turn on debugging
	neverSkipReducer: false // prevent undoable from skipping the reducer on undo/redo and clearHistoryType actions
});

Filtering Actions

If you don't want to include every action in the undo/redo history, you can add a filter function to undoable. This is useful for, for example, excluding actions that were not triggered by the user.

ngrx-undo-reducer provides you with the includeActions and excludeActions helpers for basic filtering. They should be imported like this:

import { undoable, includeActions, excludeActions } from 'ngrx-undo-reducer';

// Single Action
undoable(reducer, { filter: includeActions(SOME_ACTION) });
undoable(reducer, { filter: excludeActions(SOME_ACTION) });

// Multiple Actions
undoable(reducer, { filter: includeActions(SOME_ACTION, SOME_OTHER_ACTION) });
undoable(reducer, { filter: excludeActions(SOME_ACTION, SOME_OTHER_ACTION) });

Custom Filters

If you want to create your own filter, pass in a function with the signature (action, currentState, previousHistory). For example:

undoable(reducer, {
	filter: function filterActions(action, currentState, previousHistory) {
		return action.type === SOME_ACTION; // only add to history if action is SOME_ACTION
	}
});

// The entire `history` state is available to your filter, so you can make
// decisions based on past or future states:

undoable(reducer, {
	filter: function filterState(action, currentState, previousHistory) {
		let { past, present, future } = previousHistory;
		return future.length === 0; // only add to history if future is empty
	}
});

Combining Filters

You can also use our helper to combine filters.

import { undoable, combineFilters } from 'ngrx-undo-reducer';

function isActionSelfExcluded(action) {
	return action.wouldLikeToBeInHistory;
}

function areWeRecording(action, state) {
	return state.recording;
}

undoable(reducer, {
	filter: combineFilters(isActionSelfExcluded, areWeRecording)
});