CredibleAshok
CredibleAshok

Reputation: 73

Default selection of radio buttons not working in Angular

I have three radio buttons. I want to use them in Angular Reactive Forms. I am unable to trigger change event in case of default selection of any radio button. I want to default select Male radio button but change event on default selection does not fire. Please help me to figure out what wrong I am doing here.

I have tried to put the behaviour in stackbiz. Here is the link

https://stackblitz.com/edit/angular-radio-buttons-demo-reactive-forms-kqy3vi?file=src/app/app.component.html

My component code

import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from "@angular/forms";
  export interface Gender {
    id: number;
    value: string;
  }

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent{
 public genders: Array<Gender> = [
      {'id': 1, 'value': 'Male'},
      {'id': 2, 'value': 'FeMale'},
      {'id': 3, 'value': 'Not Specified'}
    ];
  constructor(public fb: FormBuilder) { }

  /*########### Form ###########*/
  registrationForm = this.fb.group({
    gender: ['', [Validators.required]]
  })
  // Getter method to access form control
  get myForm() {
    return this.registrationForm.get('gender');
  }
changeFired(e: any) {
  console.log('change fired before', e.value);
}

  // Submit Registration Form
  onSubmit() {
console.log(JSON.stringify(this.registrationForm.value));
  }  

}

My Html

<div class="container">
        <form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">
                <!-- Gender -->
                <div>
                    <h5>Gender</h5>
                    <div>

                        <div *ngFor="let g of genders; let i = index">
                            <input id="i" type="radio" [value]="g" name="gender" formControlName="gender" (change)="changeFired(g)">
              <label>{{g.value}}</label>
            </div>
          </div>
        </div>

          <!-- Submit Button -->
          <button type="submit" class="btn btn-danger btn-lg btn-block">Submit</button>

      </form><!-- Form ends -->
</div>

Upvotes: 1

Views: 3828

Answers (2)

SiddAjmera
SiddAjmera

Reputation: 39432

Assign a template variable to your input tag(s):

<div *ngFor="let g of genders; let i = index">
  <input 
    id="i" 
    type="radio" 
    #input
    name="gender" 
    [value]="g.id"
    formControlName="gender" 
    (change)="showMessage(g)">
  <label>{{g.value}}</label>
</div>

Then in your Component Class, access it using ViewChildren. And in the ngAfterViewInit dispatch a change event by using dispatchEvent on the nativeElement property of an appropriate item from the QueryList.

Doing that will throw an ExpressionChangedAfterItHasBeenChecked error.

So to fix that, you'll have to explicitly run the change detection again by calling this.cdRef.detectChanges(); where cdRed is the ChangeDetectorRef that I injected as a dependency.

This is how it would translate to code:

import {
  Component,
  OnInit,
  ViewChildren,
  ElementRef,
  ChangeDetectorRef,
  QueryList
} from "@angular/core";

...

@Component({...})
export class AppComponent {

  ...

  defaultSelectedOption = 3;
  @ViewChildren("input") inputs: QueryList<ElementRef>;

  ...

  constructor(public fb: FormBuilder, private cdRef: ChangeDetectorRef) {}

  /*########### Form ###########*/
  registrationForm = this.fb.group({
    gender: [this.defaultSelectedOption, [Validators.required]]
  });

  ngAfterViewInit() {
    const inputToTrigger = this.inputs.toArray()[
      this.genders.findIndex(gender => gender.id === this.defaultSelectedOption)
    ];
    (inputToTrigger.nativeElement as HTMLInputElement).dispatchEvent(
      new Event("change")
    );
    this.cdRef.detectChanges();
  }

  ...

}

Here's a Working Sample StackBlitz for your ref.

Upvotes: 1

Eldar
Eldar

Reputation: 10790

Probably you are trying to set the value something like below

ngOnInit(){
    this.myForm.setValue({id:1,gender:"Male"});
  }

This will not set your selected radio to male because it has different reference (memory address). When it comes to complex object it is always references. You should try something like below :

ngOnInit(){
    this.myForm.setValue(this.genders[0]); // this refers to male
  }

Stackblitz

Upvotes: 1

Related Questions