Reputation: 73
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
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
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
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
}
Upvotes: 1