angular 6 warning for using formControlName and ngModel

AngularAngular NgmodelAngular Reactive-Forms

Angular Problem Overview


I recently upgraded the angular version to 6-rc. I got following warning

> It looks like you're using ngModel on the same form field as > formControlName. Support for using the ngModel input property and > ngModelChange event with reactive form directives has been deprecated > in Angular v6 and will be removed in Angular v7 > > For more information on this, see our API docs here: > https://angular.io/api/forms/FormControlName#use-with-ngmodel

What does it say exactly? the link does not have any fragment for #use-with-ngmodel

I guess I need to remove ngModel and use formGroup as my data binding object.

Angular Solutions


Solution 1 - Angular

Now you can find the documentation here:

https://angular.io/api/forms/FormControlName#use-with-ngmodel-is-deprecated

So you have 3 options:

  1. use Reactive forms

  2. use Template driven forms

  3. silence warning (not recommended)

<!-- language: lang-ts -->
    imports: [
      ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'});
    ]

Solution 2 - Angular

Remove [(ngModel)] from every field within formGroup contains formControlName and set value in controller class as follows simply this.form.get('first').setValue('some value'); do not close or silence warnings explicitly

Solution 3 - Angular

add

[ngModelOptions]="{standalone: true}" 

You can read more from angular website https://angular.io/api/forms/NgModel

Solution 4 - Angular

So I stumbled upon this when trying to display users' avatars in mat-select:

<mat-form-field [formGroup]="assignedToFormGroup">
<mat-select placeholder="Assign to" [(ngModel)]="assignedTo" formControlName="assignTo">
  <mat-select-trigger>
    <img style="vertical-align:middle;" aria-hidden
      src="{{assignedToFormGroup.controls['assignTo'].value.photoUrl}}" height="20" />
    <span>@{{assignedToFormGroup.controls['assignTo'].value.userName}}</span>
  </mat-select-trigger>
  <!-- {{user.userName}} -->
  <mat-option *ngFor="let user of members" [value]="user">
    <img style="vertical-align:middle;" aria-hidden src="{{user.photoUrl}}" height="20" />
    <span>@{{user.userName}}</span>
  </mat-option>
</mat-select>

In controller, the formGroup was defined this way:

public assignedToFormGroup: FormGroup;

I followed Sohail's advice and removed [(ngModel)] from my HTML code:

<mat-form-field [formGroup]="assignedToFormGroup">
<mat-select placeholder="Assign to" formControlName="assignTo">
  <mat-select-trigger>
    <img style="vertical-align:middle;" aria-hidden
      src="{{assignedToFormGroup.controls['assignTo'].value.photoUrl}}" height="20" />
    <span>@{{assignedToFormGroup.controls['assignTo'].value.userName}}</span>
  </mat-select-trigger>
  <!-- {{user.userName}} -->
  <mat-option *ngFor="let user of members" [value]="user">
    <img style="vertical-align:middle;" aria-hidden src="{{user.photoUrl}}" height="20" />
    <span>@{{user.userName}}</span>
  </mat-option>
</mat-select>

That gave me errors when opening page - I tried to load photoUrl and userName from null, because by removing [(ngModel)] I also removed default selection in mat-select.

So I modified my controller to do the following:

  1. Constructor:

    this.assignedToFormGroup.controls['assignTo'].setValue({photoUrl: '', userName: ''});

  2. Button action where I save my form - added following line:

    let assignedTo = this.assignedToFormGroup.controls['assignTo'].value;

That actually worked. Now I'm setting default selection on page load and read selected value when submitting the form. I'm aware that it's not the best and prettiest solution, but I thought I'll share it - might be a good starting point for better solution.

Solution 5 - Angular

Using formControl(reactive Forms) is more straightforward coupled with Rxjs so Angular team changed use of it.

Change on html file

<!-- [ngModel]='model' (ngModelChange)='changed($event)' -->

to

[formControl]="myControl"

Change ts file

model: string;
  modelChanged: Subject<string> = new Subject<string>();

  changed(text: string) {
      this.modelChanged.next(text);
  }
  this.modelChanged.pipe(
      .subscribe(model => this.postErrorMessage = model);

to

this.myControl.valueChanges.pipe(
      .subscribe(model => this.postErrorMessage = model);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAkshayView Question on Stackoverflow
Solution 1 - AngularyurzuiView Answer on Stackoverflow
Solution 2 - AngularSohail AnwarView Answer on Stackoverflow
Solution 3 - AngularOlalekan J MakanjuolaView Answer on Stackoverflow
Solution 4 - AngulargreenskinView Answer on Stackoverflow
Solution 5 - AngularAhmet ArslanView Answer on Stackoverflow