Search code examples
angularformsangular-materialngmodelangular2-ngmodel

Can't bind to 'ngModel' since it isn't a known property of 'mat-select', BUT FormsModule is already imported


I'm receiving the old and very well know error: "Can't bind to 'ngModel' since it isn't a known property of 'mat-select.'" BUT

FormsModule is imported on app.module.ts.

FormsModule is imported on the component in which I am using mat-select.

NgMaterialModule also is imported.

 <mat-select formControlName="threatType" [(ngModel)]="currentThreat">

currentThreat is a string.

Dozens of google answers show the same solution: imports ForsmModule. But as you can see, FormsModule is already imported.

For what other reason could this message be generated?


Solution

  • Using the formControlName with ngModel is now deprecated. https://angular.io/api/forms/FormControlName#use-with-ngmodel-is-deprecated

    If possible and not too much effort to redesign, use new formGroup with the formControls added, and all FormValidators in one.

    A possible option I like, is to create a custom form for easy to convert back and two, if you want one form to be able to create or edit, based of data passed to a component. eg:

    export class CustomForm extends FormGroup {
    
      constructor(myDto: IMyDto) {
        const myForm = new FormGroup({
              id: myDto ? new FormControl(myDto.id) : new FormControl('', [Validators.required]),
              active: myDto ? new FormControl(myDto.active) : new FormControl(false),
            }
        );
        super(myForm.controls);
      }
    
      public toDto(): IMyDto {
        return {
          id: this.value.id,
          active: this.value.active,
        };
      }
    }
    

    Then in my component

      myForm: CustomForm;
      myDto: IMyDto; -- init at some point or passed as @Input from a parent
    
      ngOnInit(): void {
        this.myForm = new CustomForm(this.myDto);
      }
    

    and html

        <div [formGroup]="myForm">
            <input class=""
                   id="formId"
                   type="text"
                   [required]="true"
                   formControlName="id"/>
            <input class=""
                   id="formActive"
                   type="text"
                   [required]="true"
                   formControlName="active"
            />
          </div>