angularselectangular-materialangular-reactive-formsangular-forms

Issue with Patching Object Value to Angular FormControl in ngAfterViewInit


I'm working on an Angular form where I need to patch an object to a FormControl in ngAfterViewInit. However, I'm encountering an issue when trying to patch an object. Here's a simplified version of my code:

My HTML Code

<form [formGroup]="filterForm">
  <div>
    <mat-form-field fxFlex.lt-sm="auto">
      <mat-label>Action Type</mat-label>
      <mat-select formControlName="actionType">
        <mat-option *ngFor="let s of actionTypeFilter" [value]="s">
          {{ s.Name }}
        </mat-option>
      </mat-select>
    </mat-form-field>
  </div>
</form>

My TypeScript Code

actionTypeFilter = [
  {Name: 'All', Key: "All"},
  {Name: 'Allow', Key: 300201},
  {Name: 'Deny', Key: 300202},
];

ngOnInit() {
  this.filterForm = this.formBuilder.group({
    actionType: ['', Validators.required],
  });
}

ngAfterViewInit() {
  this.filterFormControls.actionType.patchValue({Name: 'All', Key: "All"});
}

get filterFormControls() { return this.filterForm.controls; }

The Problem: When I attempt to patch an object value to the FormControl in ngAfterViewInit, it doesn't work. However, if I modify the HTML to use the Key as the value, like this:

<mat-option *ngFor="let s of actionTypeFilter" [value]="s.Key"> {{ s.Name }} </mat-option>

this.filterFormControls.actionType.patchValue("All");

It works correctly, but the issue is when I console the value of actionType it will give only the Key value but i want full object of selected item.

I want to patch the entire object (e.g., {Name: 'All', Key: 'All'}) to the FormControl while keeping the original HTML structure. How can I achieve this?


Solution

  • You can use compareWith to perform the equality check for the select using the key, so we can select the entire object using this method.

    compareFn(o1: any, o2: any) {
      return o1.Key === o2.Key;
    }
    

    Full Code:

    HTML:

    <form [formGroup]="filterForm">
      <div>
        <mat-form-field>
          <mat-label>Action Type</mat-label>
          <mat-select formControlName="actionType" [compareWith]="compareFn">
            <mat-option *ngFor="let s of actionTypeFilter" [value]="s">
              {{ s.Name }}
            </mat-option>
          </mat-select>
        </mat-form-field>
      </div>
    </form>
    
    {{filterForm.value | json}}
    

    TS:

    import { ChangeDetectionStrategy, Component } from '@angular/core';
    import { MatSelectModule } from '@angular/material/select';
    import { MatInputModule } from '@angular/material/input';
    import { MatFormFieldModule } from '@angular/material/form-field';
    import {
      Validators,
      ReactiveFormsModule,
      FormGroup,
      FormBuilder,
      FormControl,
    } from '@angular/forms';
    import { CommonModule } from '@angular/common';
    /** @title Simple form field */
    @Component({
      selector: 'form-field-overview-example',
      templateUrl: 'form-field-overview-example.html',
      styleUrl: 'form-field-overview-example.css',
      standalone: true,
      imports: [
        MatFormFieldModule,
        MatInputModule,
        MatSelectModule,
        ReactiveFormsModule,
        CommonModule,
      ],
      changeDetection: ChangeDetectionStrategy.OnPush,
    })
    export class FormFieldOverviewExample {
      filterForm = new FormGroup<any>({});
      actionTypeFilter = [
        { Name: 'All', Key: 'All' },
        { Name: 'Allow', Key: 300201 },
        { Name: 'Deny', Key: 300202 },
      ];
      constructor(private formBuilder: FormBuilder) {}
    
      ngOnInit() {
        this.filterForm = this.formBuilder.group({
          actionType: ['', Validators.required],
        });
      }
    
      ngAfterViewInit() {
        this.filterFormControls.actionType.patchValue({ Name: 'All', Key: 'All' });
      }
    
      compareFn(o1: any, o2: any) {
        return o1.Key === o2.Key;
      }
    
      get filterFormControls() {
        return this.filterForm.controls;
      }
    }
    

    Stackblitz Demo