Search code examples
angularangular-materialangular-formsformgroups

Unable to create mat-radio-group from FormGroup


I am trying to create a set of radio buttons from a static set of FormControls within a FormGroup, and default checked when one is true.

Component.ts:

export class RadioOverviewExample {

  public formModel: FormGroup;

  constructor() {}

  public ngOnInit() {
    this.formModel = new FormGroup({
      formName: new FormControl(''),
      formId: new FormControl(''),
      radioOptions: new FormGroup({
        train: new FormControl(true),
        subway: new FormControl(false),
        bus: new FormControl(false),
        taxi: new FormControl(false)
      })
    })
  }    
}

HTML:

<form [formGroup]="formModel">

    <mat-radio-group formGroupName="radioOptions">
        <mat-radio-button *ngFor="let op of radioOptions.controls">
      {{op}}
    </mat-radio-button>
    </mat-radio-group>

</form>

Error:

Error: Cannot read property 'controls' of undefined

Expected Output:

[X] Train   [] Subway   [] Bus   [] Taxi

Stackblitz: https://stackblitz.com/edit/angular-kc5k9c


Solution

  • A mat-radio-group only allow choose an unique option among differents options, so you only need an unique FormControl. You use an auxiliar array to show the options -not a control in Form

    transports=[{value:0,text:"Train"},
           {value:1,text:Subway},
           {value:2,text:"Bus"},
           {value:3,text="Taxi"}
          ]
    
    <mat-radio-group formGroupName="radioOptions">
        <mat-radio-button *ngFor="let op of transports" [value]="op.value">
        {{op.text}}
       </mat-radio-button>
    </mat-radio-group>
    

    and your formModel.get('radioOptions').value becomes 0,1,2 or 3

    You can also use a mat-radio-group stand alone and use [value] and (change) to give value to the differents controls of formGroup. Remember, a FormControl exist even if we has no input control

    <mat-radio-group [value]="getIndex()"
                     (change)=setValue($event.value) 
        <mat-radio-button *ngFor="let op of transports" [value]="op.value">
        {{op.text}}
       </mat-radio-button>
    </mat-radio-group>
    

    And in .ts

      getIndex() //return the index of the first is true
      {
        return Object.keys(this.formModel.value.radioOptions).findIndex(
          x => this.formModel.value.radioOptions[x]
        );
      }
      setValue(index: number) {
        Object.keys((this.formModel.get("radioOptions") as FormGroup).controls).forEach(
          (field, i) => {
            const control=this.formModel.get("radioOptions."+field)
            if (control)
              control.setValue(i == index);
          }
        );
      }
    

    stackblitz with the last part