Skip to content

Proof of concept for creating a ngrx utility library with factories for actions, reducers, selectors and facade which simplify working with common crud operation for a given resource

Notifications You must be signed in to change notification settings

ducthang-vu/ngrx-crud-poc

Repository files navigation

NgrxCrudPoc

This project is a proof of concept for creating a ngrx utility library with factories for actions, reducers, selectors and facade which simplify working with common crud operation for a given resource.

The utility library is called ngrx-crud-util (in the libs folder). The root application is a simple example; to try it run:

npm run start-both

FEATURES

ListingAdapter

The ListingAdapter extends the ngrx standard adapter. The listing adapter's getListingInitialState return the initial state which implements the ListingState interface, the latter extending the ngrx EntityState interface:

// default ListingState returned by the listing adapter
{
      entities: {},
      ids: [],
      loading: false,
      updating: false,
      creating: false,
      deleting: false,
      error: null,
}

Consider the following example:

import { Book } from '@ngrx-crud-poc/core-data';

// In this case, we want the initial state to extend ListingState with currentId property
type BooksState = ListingState<Book> & { currentId: string }

const booksAdapter = createListingAdapter<Book, BooksState>();
const initialState: BooksState = booksAdapter.getListingInitialState({ currentId: null });

console.log(initialState)
/ *{
      entities: {},
      ids: [],
      loading: false,
      updating: false,
      creating: false,
      deleting: false,
      error: null,
      currentId: null   
} */

ListingAdapter objects expose the following reducers:

  loadEntities: (state: S) => S;
  loadEntitiesDone: (state: S, action: { payload: T[] }) => S;
  loadEntitiesError: (state: S, action: { payload: Error }) => S;

  loadEntity: (state: S) => S;
  loadEntityDone: (state: S, action: { payload: T }) => S;
  loadEntityError: (state: S, action: { payload: Error }) => S;

  createEntity:  (state: S) => S;
  createEntityDone: (state: S, action: { payload: T }) => S;
  createEntityError: (state: S, action: { payload: Error }) => S;

  updateEntity:  (state: S) => S;
  updateEntityDone: (state: S, action: { payload: T }) => S;
  updateEntityError: (state: S, action: { payload: Error }) => S;

  deleteEntity:  (state: S) => S;
  deleteEntityDone: (state: S, action: { payload: string }) => S;
  deleteEntityError: (state: S, action: { payload: Error }) => S;

listingActionCreatorFactory

Action creator factory for common crud operations.

// Example with Book entity
import { Book } from '@ngrx-crud-poc/core-data'
import { listingActionCreatorFactory } from '@ngrx-crud-poc/ngrx-crud-util';

const fromBooksActions = listingActionCreatorFactory<Book>('Books')

// create loadEntities action:
const newAction = fromBooksActions.loadEntities()

console.log(newAction)
// { type: "[Books] Load entities" }


/* fromBooksActions implements the following interface:
ngrx-crud-poc/libs/ngrx-crud-util/src/lib/actions/ListingActionCreator.ts

interface ListingActionCreator<T> {
  loadEntities: ActionCreator;
  loadEntitiesDone: CrudActionCreator<T[]>;
  loadEntitiesError: CrudActionCreator<Error>;

  loadEntity: CrudActionCreator<string>;
  loadEntityDone: CrudActionCreator<T>;
  loadEntityError: CrudActionCreator<Error>;

  createEntity: CrudActionCreator<Omit<T, 'id'>>;
  createEntityDone: CrudActionCreator<T>;
  createEntityError: CrudActionCreator<Error>;

  updateEntity: CrudActionCreator<UpdatePayload<T>>;
  updateEntityDone: CrudActionCreator<T>;
  updateEntityError: CrudActionCreator<Error>;

  deleteEntity: CrudActionCreator<string>;
  deleteEntityDone: CrudActionCreator<string>;
  deleteEntityError: CrudActionCreator<Error>;
}
*/

createListingReducer

createListingReducer is a reducer creator, which generate a reducer for a given resource by using the reducer exposed by the ListingAdapter the action generated by the listingActionCreatorFactory, and custom reducer function passed by the client.

import { fromBooksActions } from './books.actions';
import { Book } from '@ngrx-crud-poc/core-data';
import { createListingAdapter, createListingReducer, ListingState } from '@ngrx-crud-poc/ngrx-crud-util';
import { on } from '@ngrx/store';


export const BOOKS_FEATURE_KEY = 'books';

export type BooksState = ListingState<Book> & { currentId: string }

export interface BooksPartialState {
  readonly [BOOKS_FEATURE_KEY]: BooksState;
}

export const booksAdapter = createListingAdapter<Book, BooksState>();

export const initialState: BooksState = booksAdapter.getListingInitialState({ currentId: null });


// custom reducer
const updateCurrentId = (state: BooksState, action: { payload: string }): BooksState => ({
  ...state,
  currentId: action.payload
});


export const booksReducer = createListingReducer<Book, BooksState>(
  booksAdapter,
  initialState,
  fromBooksActions,
  [on(fromBooksActions.loadEntity, updateCurrentId)]  // custom reducer added
);

ListingEffects

The abstract class ListingEffects provides effects for managing crud operations.
See implementation here.

ListingFacade

The abstract class ListingFacade, to be extended and used in components and masking the ngrx store.
See implementation here.

About

Proof of concept for creating a ngrx utility library with factories for actions, reducers, selectors and facade which simplify working with common crud operation for a given resource

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published