2

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?

1
  • 1
    can you please tag the question with ngrx-forms, to make it easier to find? Commented Apr 21, 2020 at 17:38

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.