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:

    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.