How to set a different input types with reactive forms?

Viewed 85

I'm building a form with nested inputs. I've found an example of what I need and I'm trying to implement it in my app. What I don't get is how to conditionally display input type - according to the form's meta data.

Here is the markup:

<form class="tree" [formGroup]="testForm" (ngSubmit)="onSubmit()">
  <ng-template #recursiveList let-controls let-prefix="prefix" >
  
    <ng-container *ngFor="let item of controls; let i = index">
      <div class="tree-item" [formGroup]="testForm.get(prefix + i)">
       
        <input type="text" formControlName="type">
      </div>
      <div class="sub-tree" *ngIf="item.get('element')?.controls?.length">
        <ng-container
          *ngTemplateOutlet="recursiveList; context:{ $implicit: item.get('element').controls, prefix: prefix + i + '.element.'  }"></ng-container>
      </div>
    </ng-container>
  </ng-template>
  <ng-container
    *ngTemplateOutlet="recursiveList; context:{ $implicit: testForm.get('element').controls, prefix: 'element.' }"></ng-container>
</form>

Here is the meta data:

export const data: TreeItem = {
 'element': [{
'name':'age',
'label':'Age',
'fieldType':'select',
      'type': '',
      'element': [
        { 'name':'dateOfBirth',
'label':'Date Of Birth',
'fieldType':'date',
      'type': '',
      'element': []}
      ]
  }],

 };

I wonder how can I do something like:

 <input type="date" formControlName="item.name" *ngIf="item.inputType === 'date'>
 <input type="text" formControlName="item.name" *ngIf="item.inputType === 'input'>
1 Answers

I successfully achieved the result you want with the following steps that you can adapt to your situation:

FIRST create a sort of field-generator component. It gets in input a control and a field config (that includes the fieldtype AND the control you created with reactive forms).

The component looks like this:

<fields-list *ngFor="let field of fieldsList">
  <field-generator [ngSwitch]="field.fieldType">
    <input *ngSwitchCase="'inputText'" [control]="field.control" type="text" />
    <input *ngSwitchCase="'inputNumber'" [control]="field.control" type="number" />
    <div *ngSwitchDefault>Field type not supported</div>
  <field-generator/>
</fields-list>

THEN compile your configuration mapping the simple field with field + control to obtain such a structure:

fieldsList =  [{
       ...yourFieldData, // -> all the keys you need
       name, // a key or a name that identifies the field to get its control
       fieldType, // the type you need to display 
       control // the angular control (individual or part of form group)
    }, 
    ...
  ]

where 'control' is the result of the new FormControl(field.name, ...).get(field.name) method.

So basically you have these four steps:

  1. Create a JSON config with fields as you wish
  2. Create the form controls or form group you need
  3. Pass to field generator each field with its config and the form control
  4. Let field generator create each field with the type you want and all the info you need to pass (ex validation, options for selects and so on)

I found this approach really straight forward and in complex project it worked really well with tens of input of several type (for example I can display dates picker, sliders, input text and so on, simply by adding. a type and extending the config JSON)

I'm sure you will find this answer helpful, or at least, I hope so!

Related