How can I prevent NgModel from setting invalid form control values?

Issue

How can I prevent NgModel from setting invalid template-driven form control values? I verified that NgModel will set invalid values when two-way bound to a model instance. I am aware that I can create a copy of the model instance, but I may have scenarios where a save/revert approach is not appropriate.

https://stackblitz.com/edit/angular-gcu9mz

@Component({
  selector: 'my-app',
  template: `
    Enter an invalid value (less than 14 characters).
    <br><br>
    <label for="input">Input:</label>
    <input #input="ngModel" type="text" minlength="14" [(ngModel)]="value" 
      placeholder="Enter an invalid value">
    Valid: {{input.valid}}
    <br>
    Model value: {{value}}
`
})
export class AppComponent  {
  value = 'Invalid value';
}

I found many related questions for AngularJS where ngModelOptions is said to support an allowInvalid configuration that changes the default behavior. However, that does not seem to be supported in Angular’s NgModel.

Don't record invalid values with ng-model

How to prevent model to be invalid?

I am not interested in the discussion on whether accepting, displaying, or setting invalid values is good practice nor whether the model should be the “source of truth” as my requirements always depend on the application and use case.

Solution

Expanding on alexortizl’s answer, I chose to utilize getters and setters but not to duplicate the validation logic. I used the FormControl’s validity state to prevent setting invalid values on the model.

https://stackblitz.com/edit/angular-5xkael

@Component({
  selector: 'my-app',
  template: `
    <label for="input">Input:</label>
    <input #input="ngModel" type="text" minlength="14" [(ngModel)]="value">
`
})
export class AppComponent  {
  @ViewChild('input', { static: true }) input: NgControl;

  // Allow an initial invalid value.
  private _value = 'Invalid value';
  get value() { return this._value; }

  set value(value: string) { if (this.input.valid) this._value = value; }
}

Answered By – Trevor Karjanis

Answer Checked By – Willingham (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.