Search code examples
angularformsonchangeonsubmitangular2-form-validation

Angular: disable field on change and set value of field


I have a table in which I need to render database values and then after user changes I need to submit that form. Here is demo

There I need to apply like, if status is 'eliminated' or 'absent' then need to disable rank dropdown and rank will be null/0.

I am able to render details and tried on change of status to disable rank but it not working.

Please help and guide. Thanks.

Ts

import { Component } from '@angular/core';
import {
  AbstractControl,
  FormArray,
  FormBuilder,
  FormControl,
  FormGroup,
  Validators,
} from '@angular/forms';
import { merge } from 'rxjs';
import { takeWhile, tap } from 'rxjs/operators';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  name = 'Angular';
  myForm!: FormGroup;
  rankArray = [];
  rankStatusArray: any = [
    { id: 'participated', name: 'Participated' },
    { id: 'eliminated', name: 'Eliminated' },
    { id: 'absent', name: 'Absent' },
  ];
  checklist = [
    {
      id: 13,
      rank: 3,
      horse_id: 86,
      horse_name: 'test232 fdfgdg',
      life_number: null,
      country: 'Afghanistan',
      result_status: 'participated',
      comment: 'my comment',
    },
    {
      id: 12,
      rank: null,
      horse_id: 87,
      horse_name: 'test horse',
      life_number: '234234',
      country: 'Algeria',
      result_status: null,
      comment: null,
    },
    {
      id: 11,
      rank: null,
      horse_id: 88,
      horse_name: 'tesdfs',
      life_number: null,
      country: 'Afghanistan',
      result_status: null,
      comment: null,
    },
    {
      id: 10,
      rank: null,
      horse_id: 94,
      horse_name: 'nam horse',
      life_number: 'fh345',
      country: 'India',
      result_status: null,
      comment: null,
    },
  ];

  constructor(private fb: FormBuilder) {
    this.myForm = this.fb.group({
      checklist: this.fb.array([]),
    });
    this.populate();
  }

  ngOnInit(): void {
    this.rankArray = Array(4)
      .fill(1)
      .map((x, i) => i + 1);
  }

  get formChecklist() {
    return this.myForm.get('checklist') as FormArray;
  }

  populate() {
    this.checklist.forEach((x) => {
      this.formChecklist.push(
        this.fb.group({
          participantId: x.id,
          rankStatus: x.result_status,
          rank: x.rank,
          comment: x.comment,
          horse_name: x.horse_name,
          country: x.country,
          life_number: x.life_number,
        })
      );
    });
  }

  onChange(event) {
    console.log(event);
    if (event == 'eliminated' || event == 'absent') {
      this.myForm.controls['rank'].disable();
    } else {
      this.myForm.controls['rank'].enable();
    }
  }

  onSubmit() {
    console.log(this.myForm.value);
  }
}

HTML

<div class="table-responsive competition_wrapper">
  <form [formGroup]="myForm" (ngSubmit)="onSubmit()">
    <table
      class="
        bordered
        border-top-0
        table
        dark
        shadow_none
        w-100
        mb-3
        competition_result_table
      "
    >
      <thead>
        <tr>
          <th width="150" colspan="6">Competition Name</th>
        </tr>
      </thead>
      <tbody formArrayName="checklist">
        <tr class="table_sub_heading">
          <td>Status</td>
          <td>Rank</td>
          <td>Participant Name</td>
          <td>Country</td>
          <td>Life Number</td>
          <td>Comment</td>
        </tr>
        <tr
          *ngFor="let item of formChecklist.controls; let i = index"
          [formGroupName]="i"
        >
          <td>
            <div class="select_wrapper form-group mb-0">
              <select
                class="form-control"
                formControlName="rankStatus"
                (ngModelChange)="onChange($event)"
              >
                <option [ngValue]="null">Select</option>
                <option
                  *ngFor="let status of rankStatusArray"
                  [ngValue]="status.id"
                >
                  {{ status.name }}
                </option>
              </select>
            </div>
          </td>
          <td>
            <div class="select_wrapper form-group mb-0">
              <select class="form-control" formControlName="rank">
                <option value="null">Select</option>
                <option *ngFor="let rankno of rankArray" [value]="rankno">
                  {{ rankno }}
                </option>
              </select>
            </div>
          </td>
          <td>{{ item.get('horse_name').value }}</td>
          <td>
            {{ item.get('country').value }}
          </td>
          <td>
            {{ item.get('life_number').value }}
          </td>
          <td>
            <div class="form-group mb-0">
              <textarea
                type="text"
                class="form-control"
                formControlName="comment"
              ></textarea>
            </div>
          </td>
        </tr>
      </tbody>
    </table>
    <button class="btn">Add Result</button>
  </form>
</div>

<pre>{{ myForm.value | json }}</pre>

Solution

  • You're enumerating a ton of points and since this is not a free code provider app, I won't be solving them all until, at least, you try to do something.

    This being said, I created a demo that solves the first problem I see you tried and couldn't finish. You weren't able to disable the rank field because:

    • first, the event you're passing in the onchange function is not what you want. You need the event's value and even then, you need to extract the information that's important to you, the id.
    • second, you were trying to disable/enable something that didn't exist. The console was giving you errors about it. this.myForm.controls['rank'] is undefined.

    Regarding step n.4, you might need to be listening to the rank formcontrol and hide the chosen options from the next competitor's rank dropdown. Hope this gives you a hint to tackle the problem.