I have the following form with a set of radio buttons in each section I can only select one of the buttons at any given time.
It appears that they do not have unique names.
The form is dynamically generated using the following code:
get anatomicalComplaints(): FormArray {
return this.childForm.get('dcrr_pc')?.get('pc_anat_loc_compl') as FormArray
}
addAnatomicalComplaints() {
this.anatomicalComplaints.push(this.createNewAnatomicalComplaint())
}
removeAnatomicalComplaints(index: number) {
this.anatomicalComplaints.removeAt(index)
}
createNewAnatomicalComplaint() {
return new FormGroup({
spinal: new FormControl(''),
vas: new FormControl(''),
laterality: new FormControl(''),
radicular_component: new FormControl(''),
pc_cas_hist_doc_compl: new FormControl('')
})
}
Each input in the form is a custom component that I have built to make development easier. The code follows here:
import { CommonModule } from '@angular/common';
import { Component, forwardRef, Host, Input, OnDestroy, OnInit, Optional, ViewEncapsulation } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule, FormsModule, AbstractControl, FormGroupDirective, ControlContainer, FormGroup, FormArray } from '@angular/forms';
import { Subject } from 'rxjs';
@Component({
selector: 'app-form-input',
standalone: true,
imports: [
CommonModule
],
templateUrl: './form-input.component.html',
styleUrl: './form-input.component.scss',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FormInputComponent),
multi: true
},
],
viewProviders: [
{provide: ControlContainer, useExisting: FormGroupDirective}
]
})
export class FormInputComponent implements OnInit, ControlValueAccessor, OnDestroy {
@Input() placeholder: string = ''
@Input() type: string = 'text'
@Input() label: string = ''
@Input() required: boolean = false
@Input() minLength: number = 0
@Input() labelClassList: string = ''
@Input() classList: string= ''
@Input() size: string = 'sm'
@Input() options: string[] = [];
@Input() selectOptions: any;
@Input() controlName : string | null = null
@Input() indexAt : number = 0
@Input() formType : string = 'horizontal'
@Input() inputGroup : boolean = false
protected onTouched: any = () => {}
private onChange: any = () => {}
private destroy$ = new Subject<void>()
control !: AbstractControl
value: any;
constructor(public parentForm: FormGroupDirective) {
}
ngOnInit() {
}
setRadioId = (index: number) => `${this.controlName}${index}`
writeValue(value: any): void {
this.value = value
}
registerOnChange(fn: any): void {
this.onChange = fn
}
registerOnTouched(fn: any): void {
this.onTouched = fn
}
onInputChange(event: any): void {
this.value = event.target.value
this.onChange(this.value)
}
ngOnDestroy(): void {
this.destroy$.next()
this.destroy$.complete()
}
}
@if(!inputGroup) {
<div [class]="classList">
@if(label != '' && formType == 'default') {
<label>{{label}}</label>
}
@if(type == 'text' || type == 'date') {
<input
[type]="type"
[placeholder]="placeholder"
[value]="value"
(input)="onInputChange($event)"
(blur)="onTouched()"
class="form-control"
[class.form-control-sm]="size == 'sm'"
/>
}
@if(type == 'radio') {
@for(option of options; track option; let idx = $index) {
<div class="form-check form-check-inline">
<input class="form-check-input" [type]="type" [name]="controlName" [id]="setRadioId(idx)" [value]="option">
<label class="form-check-label" [for]="setRadioId(idx)">
{{option}}
</label>
</div>
}
}
@if(type == 'checkbox') {
@for(option of options; track option; let idx = $index) {
<div class="form-check">
<input [type]="type" class="form-check-input" [name]="controlName">
<label class="form-check-label">
{{option}}
</label>
</div>
}
}
@if(type == 'select') {
<select class="form-control" [class.form-control-sm]="size == 'sm'" (input)="onInputChange($event)"
(blur)="onTouched()">
<option value="">--Payer--</option>
<option *ngFor="let o of selectOptions" [value]="o">{{o}}</option>
</select>
}
@if(type == 'textarea') {
<textarea class="form-control" [class.form-control-sm]="size == 'sm'" rows="5" width="100%"></textarea>
}
</div>
}
@if(inputGroup) {
<div [class]="classList">
<div class="input-group">
<span class="input-group-text border-0 bg-transparent">{{label}}</span>
@if(type == 'text' || type == 'date') {
<input
[type]="type"
[placeholder]="placeholder"
[value]="value"
(input)="onInputChange($event)"
(blur)="onTouched()"
class="form-control"
[class.form-control-sm]="size == 'sm'"
/>
}
@if(type == 'select') {
<select class="form-control" [class.form-control-sm]="size == 'sm'" (input)="onInputChange($event)"
(blur)="onTouched()">
<option value="">--Payer--</option>
<option *ngFor="let o of selectOptions" [value]="o">{{o}}</option>
</select>
}
</div>
</div>
}
I have tried passing in the unique indexes, setting the formControlName inside the custom component, and setting unique ids. None of these solutions have worked.
I have a working stackblitz application here
https://stackblitz.com/edit/stackblitz-starters-pr7ac5dg?file=src%2Ftemplate.html
Steps to Replicate
Expected Outcomes
You will only be able to select one radio button in the whole group
Desired Outcome
Select any number of radio buttons in the array
The radio button all have the same name
attribute, that is why the selection jumps between rows. The name property decides the radio button groupings and toggling action behaviour.
Create the unique name
based on the row index indexAt
:
<div class="form-check form-check-inline">
<input
class="form-check-input"
[type]="type"
[name]="controlName + '_' + indexAt"
[id]="setRadioId(idx)"
[value]="option"
/>