Home > Blockchain >  Angular Dynamic Radio Buttons using Reactive Forms
Angular Dynamic Radio Buttons using Reactive Forms

Time:04-06

I am working on an Angular 12 application. It has a table with multiple rows populated dynamically. Each row has four columns. The third column has radioButton Yes No as shown.

  • Desired Output: Example, if the table has three rows and I want to select Yes Radio button in first row, No in second and I don't want to select any in third row, it should be allowed.

enter image description here

  • Actual Output: It is letting me select only one row with either Yes or No.

My html to be populated dynamically : marks-input-component.html

<ng-container *ngIf="!!markForm" [formGroup]="markForm">
  <ng-container *ngIf="inputType === inputEnum.RADIO_BUTTON">
    <fieldset>
      <ng-container *ngFor="let item of options">
        <div >
          <input type="radio" [formControl]="oneInputControl" id="{{ item.markId }}-{{ item.id }}" [value]="item.id">
          <label for="{{ item.markId }}-{{ item.id }}">&nbsp;{{ item.option }}</label>
        </div>
      </ng-container>
    </fieldset>
  </ng-container>
<br>

My dynamic ts file : marks-input-component.ts

export class MarksInputComponent implements OnInit{
  @Input() inputType: string;
  @Input() markId: number;
  @Input() markForm: FormGroup;

  options: MarkOption[];
  
    ngOnInit(): void {
    super.ngOnInit();
    this.initOptions();
    this.connectListeners();
  }
  
    private connectListeners() {
    this.onOneInputChange();
  }

  private onOneInputChange() {
    this.oneInputControl.valueChanges.pipe(
      takeUntil(this.destroyed$),
      tap((value) => {
        const id = parseInt(value);
        if (id) {
          const option = this.options.find(v => v.id === id);
          option ? this.markForm.controls.mark.patchValue(option.mark) : this.markForm.controls.mark.patchValue(undefined);
        } else {
          this.oneInputControl.patchValue(-1, { onlySelf: true, emitEvent: false });
          this.markForm.controls.mark.patchValue(undefined);
        }
      })
    ).subscribe();
  }
  
  get responses() {
    return this.markForm.controls.responses as FormArray;
  }

  get oneInputControl() {
    const f = this.responses.controls[0] as FormGroup;
    return f.controls.markId as FormControl;
  }
  }

The html page: marks-component.html

<ng-container *ngFor="let markForm of allMarkForms.controls">
    <ng-container *ngFor="let markResponse of manualMarks; let rowNum = index">
        <ng-container *ngIf="markForm.controls.markId.value === markResponse.markId">
            <tr id="manual-mark-response-row-{{ rowNum }}" }}">
                <td id="mark-id-{{ rowNum }}">{{ markResponse.markIdText }}</td>
                <td id="mark-text-{{ rowNum }}">{{ markResponse.markText }}</td>
                <td id="mark-mark_description-{{ rowNum }}">
                        <!-- marks input component -->
                    <app-dynamic-input
                          [inputType]="markResponse.inputType"
                          [markId]="markResponse.markId"
                          [markForm]="markForm"></app-dynamic-input>
                    
                </td>
                 <td id="mark-mark-{{ rowNum }}">
                    <ng-container *ngIf="markResponse.inputType === inputEnum.RADIO_BUTTON">
                          {{ markForm.controls.mark.value }}
                     </ng-container>
           
                 </td>
            </tr>
        </ng-container>
    </ng-container>
</ng-container>

CodePudding user response:

You're assigning the same FormControl to each input, so they will act as a single input group. In reality, you need a unique FormControl for each yes / no pair.

Here's a simple example of a form with three yes / no questions

export class OneComponent {
  myFormGroup = new FormGroup({
    q1: new FormControl(),
    q2: new FormControl(),
    q3: new FormControl(),
  });

  get allControlNames() {
    return Object.keys(this.myFormGroup.controls);
  }
}
<form [formGroup]="myFormGroup">
  <ng-container *ngFor="let controlName of allControlNames">
    <label>
      <input type="radio" [value]="true" [formControlName]="controlName" />
      <span>YES</span>
    </label>
    <label>
      <input type="radio" [value]="false" [formControlName]="controlName" />
      <span>NO</span>
    </label>
    <br />
  </ng-container>
</form>

Use formControlName="" to select a specific FormControl from the encapsulating FormGroup.

CodePudding user response:

In the input type radio, I was missing unique name field for each yes / no pair. Adding name="{{ item.markId }}-test" this worked for me.

<input type="radio" name="{{ item.markId }}-test" [formControl]="oneInputControl" id="{{ item.markId }}-{{ item.id }}" [value]="item.id">
  • Related