I am using an ngrx-forms library for managing states of my form.
This is the library : https://ngrx-forms.readthedocs.io/
It works well with simple inputs for me. But when it comes to dynamic controls, I am not sure how to use it.
For example, let's say we have a form:
myform = this.fb.group({
topic: '',
books: [''],
languages: [''],
})
now the languages controls looks like this :
{language: '', code: ''}
How can I dynamically add the above control to the languages array of form builder when the user clicks add languages button? I can do it with a regular FormBuilder. No problem.
but when it comes to managing state using ngrx coupled with ngrx-forms how can I create a reducer function to add language controls dynamically?
Author of ngrx-forms here.
Take the following component that builds a form as you describe above with @angular/forms
.
export class ExampleComponent {
private formBuilder = new FormBuilder();
private form = this.formBuilder.group({});
buildForm() {
this.form = this.formBuilder.group({
topic: '',
languages: this.formBuilder.array([]),
});
this.addLanguageControlGroup();
}
addLanguageControlGroup(lang?: string, code?: string) {
const newControl = this.formBuilder.group({
language: lang || '',
code: code || '',
});
(this.form.get('languages') as FormArray).push(newControl);
}
}
With ngrx-forms the code would be a reducer like this (using ngrx v8+):
interface MyFormValue {
topic: string;
languages: LanguageFormValue[];
}
interface LanguageFormValue {
language: string;
code: string;
}
const INITIAL_FORM_VALUE: MyFormValue = {
topic: '',
languages: [
{
language: '',
code: '',
},
],
};
const myFormReducer = createReducer(
{
formState: createFormGroupState('MY_FORM', INITIAL_FORM_VALUE),
},
onNgrxForms(),
);
In your component, you could then have something like this:
export class NgrxFormsExampleComponent {
@Input() formState: FormGroupState<MyFormValue>;
constructor(private actionsSubject: ActionsSubject) { }
addLanguageControlGroup(lang?: string, code?: string) {
this.actionsSubject.next(
new AddArrayControlAction<LanguageFormValue>(
this.formState.controls.languages.id,
{
language: lang || '',
code: code || '',
},
)
);
}
}
Instead of using the built-in AddArrayControlAction
from ngrx-forms you could also create your own action and then add the control in the reducer, like this:
const addLanguageControlGroup = createAction(
'MY_FORM/addLanguageControlGroup',
(lang?: string, code?: string) => ({ lang, code }),
);
const myFormReducer = createReducer(
{
formState: createFormGroupState('MY_FORM', INITIAL_FORM_VALUE),
},
onNgrxForms(),
on(addLanguageControlGroup, ({ formState }, { lang, code }) => ({
formState: updateGroup(formState, {
languages: addArrayControl({
language: lang || '',
code: code || '',
}),
}),
})),
);
export class NgrxFormsExampleComponent {
@Input() formState: FormGroupState<MyFormValue>;
constructor(private actionsSubject: ActionsSubject) { }
addLanguageControlGroup(lang?: string, code?: string) {
this.actionsSubject.next(addLanguageControlGroup(lang, code));
}
}
I hope this helps.