Search code examples
angularangular-materialangular-reactive-formsangular-forms

Error: control.registerOnChange is not a function with reactive form


I am trying to get the mat-select to open with 'tag2' selected. It works with a string[] but not with { id: number; name: string }[].

  tags: { id: number; name: string }[] = [{ id: 1, name: 'tag1' }, { id: 2, name: 'tag2' }, { id: 3, name: 'Jack' }];

  form = this.fb.group({
    loadSettings: this.fb.group({
      test: this.fb.group({
          id: [2, Validators.required],
          name: ['tag2', Validators.required],
      }),
}),  });

<form [formGroup]="form">
  <div formGroupName="loadSettings">
    <div class="au-mat-column-lg-px" style="padding-top: 76px;">
      <mat-form-field class="full-width">
        <mat-select [compareWith]="compareFn" formControlName="test">
          <mat-option *ngFor="let option of tags" [value]="option">
            <span>{{ option.name }}</span>
          </mat-option>
        </mat-select>
      </mat-form-field>
    </div>
  </div>
</form>

https://stackblitz.com/edit/angular-15-starter-pack-dxetmw

Any help much appreciated!


Solution

  • You are getting the error "Error: control.registerOnChange is not a function with reactive form", because the ts form control name, does not match the formControlName attribute value you have in the HTML.

    I am not sure why you need two formGroups, but we can use the ID to set the tag value, you do not need a formGroup for each id and name, instead just a single value id will be used for selection.

    HTML:

    <form [formGroup]="form">
      <div formGroupName="loadSettings">
        <div class="au-mat-column-lg-px" style="padding-top: 76px;">
          <mat-form-field class="full-width">
            <!-- <mat-label>Revision Tag</mat-label> -->
            <mat-select formControlName="test">
              <mat-option *ngFor="let option of revisionTags" [value]="option.id">
                <span>{{ option.name }}</span>
              </mat-option>
            </mat-select>
          </mat-form-field>
        </div>
      </div>
    </form>
    

    TS:

    import { Component, OnInit } from '@angular/core';
    import { FormBuilder, Validators } from '@angular/forms';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
    })
    export class AppComponent {
      constructor(private fb: FormBuilder) {}
    
      revisionTags: { id: number; name: string }[] = [
        { id: 1, name: 'tag1' },
        { id: 2, name: 'tag2' },
        { id: 3, name: 'Jack' },
      ];
      //revisionTags: string[] = ['Jack', 'Tom', 'Donald'];
    
      form = this.fb.group({
        loadSettings: this.fb.group({
          //test: ['Tom', Validators.required],
          test: [1, Validators.required],
        }),
      });
    
      compareFn(o1: any, o2: any): boolean {
        // if (o2 === null) {
        //     return false;
        // }
        return o1.id === o2.id;
      }
    }
    

    Stackblitz Demo