Skip to content

Commit

Permalink
feat: allow onNgrxForms to work on form states directly instead of …
Browse files Browse the repository at this point in the history
…requiring form states to be direct children of reduced states
  • Loading branch information
MrWolfZ committed May 31, 2020
1 parent b9e8b1b commit b81abb4
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 2 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
## ngrx-forms Changelog

<a name="6.3.0"></a>
### 6.3.0

#### Features

* allow `onNgrxForms` to work on form states directly instead of requiring form states to be direct children of reduced states

<a name="6.2.0"></a>
### 6.2.0

Expand Down
25 changes: 24 additions & 1 deletion docs/user-guide/updating-the-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ If you are using ngrx version 8 or above you can alternatively use `onNgrxForms`

```ts
import { createReducer } from '@ngrx/store';
import { onNgrxForms, wrapReducerWithFormStateUpdate } from 'ngrx-forms';
import { onNgrxForms, onNgrxFormsAction, wrapReducerWithFormStateUpdate } from 'ngrx-forms';

const rawReducer = createReducer(
initialState,
Expand Down Expand Up @@ -87,6 +87,29 @@ export const reducer = wrapReducerWithFormStateUpdate(
);
```

`onNgrxForms` also works if the reduced state itself is a form state:

```ts
import { createReducer } from '@ngrx/store';
import { onNgrxForms, wrapReducerWithFormStateUpdate } from 'ngrx-forms';

const initialState = createFormGroupState('loginForm', initialLoginFormValue)

// this reducer is equivalent to the `formStateReducer` provided by
// ngrx-forms, but it allows you simple composition of additional
// action handlers; this style also makes your reducer more consistent
// with your other reducers that use `onX` handlers
export const reducer = createReducer(
initialState,

// this function automatically calls the appropriate reducer
// for the form state
onNgrxForms(),

// your other reducers...
);
```

Below you will find a complete list of all update functions provided by **ngrx-forms**. Each section also shows how to use actions directly instead of the update functions (the examples directly call the `formStateReducer` but you can of course dispatch these actions from anywhere in your code). To view all available actions the best place is [the code itself](https://github.com/MrWolfZ/ngrx-forms/blob/master/src/actions.ts).

#### Setting the value
Expand Down
38 changes: 38 additions & 0 deletions src/reducer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,18 @@ describe(onNgrxForms.name, () => {
};

const resultState = onNgrxForms<typeof state>().reducer(state, new MarkAsTouchedAction(FORM_CONTROL_INNER_ID));
expect(resultState.form.id).toBe(INITIAL_STATE.controls.inner.id);
expect(resultState.form).not.toBe(INITIAL_STATE.controls.inner);
});

it('should call the reducer for top-level controls', () => {
const state = INITIAL_STATE.controls.inner;

const resultState = onNgrxForms<typeof state>().reducer(state, new MarkAsTouchedAction(FORM_CONTROL_INNER_ID));
expect(resultState.id).toBe(INITIAL_STATE.controls.inner.id);
expect(resultState).not.toBe(INITIAL_STATE.controls.inner);
});

it('should call the reducer for groups', () => {
const state = {
prop: 'value',
Expand All @@ -148,6 +157,14 @@ describe(onNgrxForms.name, () => {
expect(resultState.form).not.toBe(INITIAL_STATE);
});

it('should call the reducer for top-level groups', () => {
const state = INITIAL_STATE;

const resultState = onNgrxForms<typeof state>().reducer(state, new MarkAsTouchedAction(FORM_CONTROL_ID));
expect(resultState.id).toBe(INITIAL_STATE.id);
expect(resultState).not.toBe(INITIAL_STATE);
});

it('should call the reducer for arrays', () => {
const state = {
prop: 'value',
Expand All @@ -158,6 +175,14 @@ describe(onNgrxForms.name, () => {
expect(resultState.form).not.toBe(INITIAL_STATE.controls.inner5);
});

it('should call the reducer for top-level arrays', () => {
const state = INITIAL_STATE.controls.inner5;

const resultState = onNgrxForms<typeof state>().reducer(state, new MarkAsTouchedAction(FORM_CONTROL_INNER5_ID));
expect(resultState.id).toBe(INITIAL_STATE.controls.inner5.id);
expect(resultState).not.toBe(INITIAL_STATE.controls.inner5);
});

it('should work with createReducer', () => {
const state = {
prop: 'value',
Expand All @@ -180,6 +205,19 @@ describe(onNgrxForms.name, () => {
resultState = reducer(state, new MarkAsTouchedAction(FORM_CONTROL_INNER5_ID));
expect(resultState.array).not.toBe(INITIAL_STATE.controls.inner5);
});

it('should work with createReducer for top-level form state', () => {
const state = INITIAL_STATE;

const reducer = createReducer(
state,
onNgrxForms(),
);

const resultState = reducer(state, new MarkAsTouchedAction(FORM_CONTROL_ID));
expect(resultState.id).toBe(INITIAL_STATE.id);
expect(resultState).not.toBe(INITIAL_STATE);
});
});

describe(onNgrxFormsAction.name, () => {
Expand Down
2 changes: 1 addition & 1 deletion src/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function reduceNestedFormStates<TState>(state: TState, action: Action): TState {
*/
export function onNgrxForms<TState = any>(): { reducer: ActionReducer<TState>; types: string[] } {
return {
reducer: (state, action) => reduceNestedFormStates(state!, action),
reducer: (state, action) => isFormState(state) ? formStateReducer(state!, action) as unknown as TState : reduceNestedFormStates(state!, action),
types: ALL_NGRX_FORMS_ACTION_TYPES,
};
}
Expand Down

0 comments on commit b81abb4

Please sign in to comment.