Dynamic self-registered FormControl in Angular

Angular is very flexible framework, that’s the power! We can use different ways to do same things.

Anton Marinenko
2 min readOct 18, 2021

Example for start

We have a list of items with FormGroup, it should looks like checklist, and we should make it works.

Some component with ckecklist:

some.component.html<p>Checklist:</p><app-check-list [list]=”list$ | async”></app-check-list>

Component for checklist:

check-list.component.html<ul [formGroup]=”formGroup”>  <li *ngFor=”let item of list”>    <input [formControlName]=”item” type=”checkbox” [id]=”item” />    <label [for]=”item”>{{ item }}</label>  </li></ul>check-list.component.ts@Component({  selector: ‘app-check-list’,  templateUrl: ‘./check-list.component.html’,  styleUrls: [‘./check-list.component.css’],  changeDetection: ChangeDetectionStrategy.OnPush,})export class CheckListComponent {  @Input()  list: string[];
readonly formGroup = new FormGroup({});}

At this moment example shows an error, because our FormGroup is empty and we use controls within.

Static declaring FormGroup

If you go static way to declare FormGroup, it should for example looks like:

readonly formGroup = new FormGroup({  apple: new FormControl(),  banana: new FormControl(),  orange: new FormControl(),  grape: new FormControl(),  kiwi: new FormControl(),});

And then if the list property has same values: [‘apple’, ‘banana’, ‘orange’, ‘grape’, ‘kiwi’], — example would works well.

But it works for static, what if we don’t know our list of controls? Then we need dynamic solution.

Dynamic declaring FormGroup

Here is how example should look for a dynamic solution:

readonly formGroup = new FormGroup({});

Keep FormGroup empty as at start.

check-list.component.html<ul [formGroup]=”formGroup”>  <li *ngFor=”let item of list”>    <input 
[formControl]=”newFormControl(item)”
type=”checkbox”
[id]=”item” />
<label [for]=”item”>{{ item }}</label> </li></ul>

FormGroup in Angular has method registerControl, which returns registered control. That’s all we need! Just add newFormControl() method to component:

check-list.component.ts...export class CheckListComponent {...  readonly formGroup = new FormGroup({});...  newFormControl(field: string): FormControl {    return this.formGroup.registerControl(field, new FormControl()) as FormControl;  }}

Now every control register itself in the FormGroup.

Thanks.

--

--

Anton Marinenko

I love Angular and web development! I'm writing articles and helping people love Angular as much as I do. Currently working at TSUM Moscow.