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-effects

v0.1.1

Published

Enables undo-able actions with side effects for NgRx

Downloads

2

Readme

ngrx-undo-effects

Package to enable undo-able NgRx actions with side effects.

Overview

This feature enables undo functionality on explicitly defined NgRx actions. From a high level, it allows the developer to create actions with associated undo actions. When these actions are dispatched, the corresponding undo action will be added to an array in the store. Later, if the user wants to undo this action, an undoLastAction action can be dispatched, which will pull the most recent undo action out of the store, and dispatch it.

Setup

Import NgrxUndoEffectsModule in app.module.ts, and add undoMetaReducer to the metaReducers array in StoreModule.forRoot

@NgModule({
  ...
  imports: [
    ...
    StoreModule.forRoot({
      reducer,
      { metaReducers: [
        ...
        undoMetaReducer    // Add this
      ]}
    }),
    NgrxUndoEffectsModule  // Add this
  ]
})

Usage

The package contains a function createUndoableSuccessAction which enables the creation of paired action (request/response) and enforces a specific set of rules regarding actions/undo actions. Specifically, the following rules are enforced:

  • When creating the success action, an undo action factory must be provided. This factory function accepts the current state and the request action, and returns a new action which would undo the changes made by the request action.
  • When dispatching the response (success) action, the typings require the user to pass in the request action to the response action.

Undo

To undo the last action saved in the store, simply dispatch undoLastAction.

this.store.dispatch(undoLastAction());

The list of actions can be retrieved using the undoActions selector.

this.undoActions$ = this.store.pipe(select(undoActions));

Example Flow

If we have a key in the store called name as follows:

{
  name: string;
}

If we send an action to the API to update the key, we might have an action like this:

fromActions.updateName({ name: 'newName' })

In order to reverse this change, we would need to provide a factory to create an action to reverse this change.

(state, action) => fromActions.updateName({ name: store.name })

Here we can see that we are creating a new action (updateName), with a payload based on the current name from the store. In this case, we didn't need the request action, because it only contained the new name.

Another example

Here is a more complex example which would require the use of the action parameter. Consider the scenario of updating an array of items. For example, if we have a key in the store with a list of items as follows:

{
  items: [
    { id: number, name: string }
  ]
}

In order to send an action to the API to update the name of the item with id of '5', we might have an action like this:

fromActions.updateItemNames({ 
  items: [ 
    { id: 5, name: 'newName' } 
  ] 
})

To reverse this change, we would need to provide a factory to create an action to reverse this change.

(state, action) => fromActions.updateItemNames({
  items: {
    action.items.map((item) => ({
      id,
      name: store.items.find((item) => item.id === id).name
    }))
  }
)

Here we can see that we are creating a new action (updateItemNames), with a payload based on the request actions payload. To generate the undo payload, we take the items from the request action ({ id: 5, name: 'newName' } from the earlier example), and extract the current name for each one from the store.

Creating New Undo-able Actions

Due in large part to the code in posts.undo.ts, the creation of new undo-able action is simple, using the createUndoableSuccessAction function.

// Create the request action normally, using `createAction`

export const updatePostName =                  // Name of the new request Action
  createAction(
    '[Posts] Update Post Name',                // Type of new request Action
    props<UpdatePostNameRequest>(),            // Payload of the request Action.  Use the `props` helper function from NgRx.
  )

// Create the response action using `createUndoableSuccessAction`

export const updatePostNameSuccess =           // Name of the new response Action
  createUndoableSuccessAction(
    updatePostName                             // The request action we are creating a response action for.
    props<UpdatePostNameResponse>(),           // Payload of the response Action.  Use the `props` helper function from NgRx.
    (state: State, action: Action) =>          // Undo action factory.
      updatePostName({
        postId: state?.post?.postId,
        postName: state?.post?.postName,
      })
  );

The resulting actions (updatePostName and updatePostNameSuccess above) can be dispatched just like any other NgRx action.

The expectation is that the response/success action would be dispatched from an effect. Please note that requestAction is a required field for the success/response action.