-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using ngrx-forms with createReducer? #147
Comments
Thanks for making me aware of this. It's good to see ngrx is finally also trying to remove some of its boilerplatiness. Sadly, it is not possible out of the box right now, but as soon as ngrx 8 is released I can provide a reducer that fits the new pattern. For now, you can do that yourself, though it is a bit ugly. Something like this should work (though I haven't tested it): export const ALL_NGRX_FORMS_ACTION_TYPES: Actions<any>['type'][] = [
SetValueAction.TYPE,
SetErrorsAction.TYPE,
SetAsyncErrorAction.TYPE,
ClearAsyncErrorAction.TYPE,
StartAsyncValidationAction.TYPE,
MarkAsDirtyAction.TYPE,
MarkAsPristineAction.TYPE,
EnableAction.TYPE,
DisableAction.TYPE,
MarkAsTouchedAction.TYPE,
MarkAsUntouchedAction.TYPE,
FocusAction.TYPE,
UnfocusAction.TYPE,
MarkAsSubmittedAction.TYPE,
MarkAsUnsubmittedAction.TYPE,
AddGroupControlAction.TYPE,
RemoveGroupControlAction.TYPE,
AddArrayControlAction.TYPE,
RemoveArrayControlAction.TYPE,
SetUserDefinedPropertyAction.TYPE,
ResetAction.TYPE,
SwapArrayControlAction.TYPE,
MoveArrayControlAction.TYPE,
];
export const onNgrxForms: On<FormState<any>> = {
reducer: formStateReducer,
types: ALL_NGRX_FORMS_ACTION_TYPES,
} |
@MrWolfZ I was looking at the same thing. Our company uses ngrx-forms a lot, and we're excited for ngrx v8. If you want, the beta versions for ngrx 8 are already out, so I'd be glad to work with you on a PR for ngrx-forms that supports it. |
That looks awesome, is it in 5.0 already? One problem: What if you additionally need/want to react to a ngrxForm Action yourself? We have a use case where we run the SetValueAction through the I am wondering if running the formsReducer in a metareducer might be an idea to decouple things? |
This is what works for us:
This can be used on States that have a property with a FormState in them. Usage is like this:
@MrWolfZ Would be great if you could put |
I have just released version 5.1.0 which provides a I decided to use a different implementation than @magnattic suggested above since that approach does not work if you have multiple forms in your state (due to how For those interested in the code, note that I have intentionally not referenced the |
Nice work @MrWolfZ 👍 Still, I can't find a nice way to use pure ngrx-forms actions with this new syntax. Rough example: export const reducer = createReducer(
initialState,
onNgrxForms(),
onNgrxFormsAction(SetValueAction.TYPE, (state, action) => /* ... do something ... */),
);
export function onNgrxFormsAction<TState, TAction extends Actions<any>>(
action: TAction['type'],
reducer: (fs: TState, a: TAction) => TState
): { reducer: ActionReducer<TState>; types: string[] } {
return {
reducer,
types: [action],
};
} |
@MrWolfZ can you also include the example in the main docs? I couldn't find the proper usage until I came here. |
additionally, i'll add that AoT may not play nice with exporting the reducer as a constant – the ngrx team said this, and encourages wrapping in a reducer function. If that's the case, I'd also include the following in the docs: export function reducer(state = initialState, action: actions.Actions): State {
return wrapReducerWithFormStateUpdate(taskFormReducer, (s: State) => s.taskForm, taskFormValidator)(state, action)
} |
@wbhob the example is already in the main docs here. I would also expect people to look at the changelog when they update to a new version, and the changelog contains the example. Regarding exporting the reducer, that completely depends on your particular reducer structure. That AoT issue only applies in certain situations. I don't think it is the responsibility of this library to ensure people know how to use ngrx 8 properly. @dzonatan I just release version 5.2.0 which adds |
@MrWolfZ Thank you! So if you're using export const reducer = createReducer(
initialState,
onNgrxForms(),
onNgrxFormsAction(SetValueAction.TYPE, (state, action) => {
// manually reduce SetValueAction as it was skipped on `onNgrxForms`
state = formGroupReducer(state, action);
// do what you need..
return state;
}),
); Not sure how this can be improved at the moment - just want to point this out for others to don't miss. |
@MrWolfZ thanks! Also I found another limitation: all these helpers ( export interface FormModel {
controlA: string;
controlB: boolean;
}
export const initialState = createFormGroupState<FormModel>('EXAMPLE', { controlA: 'alpha', controlB: true });
export const rawReducer = createReducer(
initialState,
onNgrxForms(), // does nothing as it goes only through keys of the state, so never finds a form
);
// this does not work either, although its not a huge deal as you can write this purely[*]
export const reducer = wrapReducerWithFormStateUpdate(
rawReducer,
s => s,
validateForm,
);
// [*]
//export const reducer = (state: State, action: Action) =>
// validateAndUpdateForm(rawReducer(state, action)); |
@MrWolfZ while current users will read the changelog, new users will not (and should not be expected to) read the whole changelog when they install this package. Up to you, of course, but it could prevent user frustration in the future. |
Hey @MrWolfZ I started using the library for a very complex and large form and bumped into the issue mentioned in the last comment by @dzonatan . How can I solve this? Any help would be much appreciated! Thanks in advance! |
@boehmers You mean you want to create a reducer for the form state itself with // type annotations left out for simplicity
// create your reducer how you want it without using onNgrxForms
const myReducer = createReducer()
// create your update function, e.g. for validation
const validateMyForm = updateGroup({
// ...
})
// then create a combined reducer that first calls formStateReducer,
// then the custom reducer and finally the form state update
const combinedReducer = (state, action) =>
validateMyForm(
myReducer(
formStateReducer(state, action),
action,
)
) |
@MrWolfZ that worked! Thanks a lot for your effort and the quick answer, appreciate it! |
Hello, I re-thought my idea and wanted to share the result here, because other people might have the same problem. ngrx-forms creates a huge, nested state, which is IMHO fine, as long as you don't start to try to write custom reducers and modify this state by hand. See this example case:
My initial idea was to write a reducer that creates a new form state based on the values, which means fun with the spread-operater and huge nested reducers. As I already used effects to make api calls, why not use them to handle form-side-effects? So the better solution was to write effects that listen to ngrx-forms-actions and fire actions that do what I desired, e.g. an effect that equals the values of the above example if the flag is set:
|
Is there a recommended way how to use ngrx-forms with the new reducer creators from ngrx 8?
How would I link this up with the formsReducer? Is it even possible or do we have to stick with the old fashioned way for now?
The text was updated successfully, but these errors were encountered: