1

While certainly this is a case of "bad method signature reading", this is not a duplicate of the suggested question, as what's been asked here is how to create a FormGroup object dinamically from scratch, not how to append controls to an already existing FormGroup object


I'm trying to create a component that dynamically renders a reactive form based on a custom input object, which defines the inputs to be rendered within the form;

I haven't got to the input part yet, currently I've defined a sample input object in the component's class itself:

interface FieldDefinition {
    id: string,
    label: string,
    type: string,
    validatorsList: any[]
}

fieldDefinitions: FieldDefinition[] = [
    { ... }
    {
        id: 'nome',
        label: 'Nome:',
        type: 'text',
        validatorsList: [
            CommonValidators.validatorsDef.fieldHasStdVarcharLength,
            CommonValidators.validatorsDef.fieldIsEmpty,
            CommonValidators.validatorsDef.nomeCognomeContainsInvalidCharacters
        ]
    },
    { ... }
}

CommonValidators is a class I've defined elswhere and that I imported into the component, which exposes some custom "validator objects", each containing a reference to the function to be invoked during validation (among other stuff), so, in order to access the reference to the validator function to be passed to FormBuilder.group(), one would do: CommonValidators.validatorsDef.fieldHasStdVarcharLength.funcRef.

Now for the life of me, I can't figure out how to instantiate an object that FormBuilder.group() would accept starting from this.

I figured the FormBuilder.group() method would accept a Map element as a parameter, so I've tried building a map iterating over fieldDefinitions:

constructor(private formBuilder: FormBuilder) {
    let formGroupMap = new Map();

    this.fieldDefinitions.forEach(elem => {
        formGroupMap.set(
            elem.id,
            new FormControl(
                '',
                elem.validatorsList.map(elem => {
                    return elem.funcRef;
                })
            )
        );
    })

    this.form = this.formBuilder.group(formGroupMap)

    console.log(formGroupMap)
    console.log(this.form)
}

Of course this doesn't work, so I gather passing a map is not the way to go;

What kind of object should I pass to FormBuilder.group() in order to have fields correctly instantiated?

Of course I don't need the exact solution, but just the kind of object that I should actually pass, so I can instantiate it in my constructor.

Below is some console output, showing how the controls are not instantiated and how I structured the map:

enter image description here

enter image description here

enter image description here

kos
  • 510
  • 3
  • 18
  • Does this answer your question? [addControl to FormGroup dynamically in Angular](https://stackoverflow.com/questions/47573797/addcontrol-to-formgroup-dynamically-in-angular) – Gaël J Jun 20 '21 at 18:32
  • @GaëlJ Thanks a lot, unfortunately not really, those answers explain how to add FormControls to an already instantiated FormGroup object, while what I need to do is to create one from scratch. It'd seem a bit silly to instantiate a FormGroup object with a dummy control only to remove it and add the others dinamically :) – kos Jun 21 '21 at 00:44

1 Answers1

2

You can use a simple object like this to create a form with formbuilder.group():

    const formObj = {};
    this.fieldDefinitions.map(x => {   
      formObj[x.id] = {value: '', validators: x.validatorsList} 
    })
        
    this.form = this.formBuilder.group(formObj);

The formbuilder.group() can use objects with validators or disabled property like this:

this.formBuilder.group({
   name: '',
   description: {value: null, disabled: false, validators: [Validators.required]}
   property: [null, [Validators.required]]
})
Havald
  • 691
  • 8
  • 9
  • Indeed, I swear I checked the method signature multiple times and couldn't figure it out for some reason. Thanks a lot man – kos Jun 21 '21 at 00:30