Angular manually update ngModel and set form to dirty or invalid?
Asked Answered
A

5

18

I have a form and an underlying model like this

From component

myTextModel: string;
updateMyTextModel(): void {
    this.myTextModel = "updated model value";
    //todo- set form dirty (or invalid or touched) here
}

Html template

<form #testForm="ngForm" id="testForm">
  <input type="text" id="myText" [(ngModel)]="myTextModel" name="myText" #myText="ngModel">
</form>
<button (click)="updateMyTextModel()">Update myTextModel</button>
<div *ngIf="testForm.dirty">testForm diry</div>
<div *ngIf="testForm.touched">testForm touched</div>

How do I set the form touched or dirty from code?

Note: In this example i use a button to trigger the model change, but i also might update the model in other ways, such as in a callback from an web api async request.

Adal answered 1/12, 2017 at 8:9 Comment(0)
T
26

Solution:

//our root app component
import {Component, NgModule, VERSION} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { Component, ViewChild } from '@angular/core';
import { FormsModule }   from '@angular/forms';

@Component({
  selector: 'my-app',
  template: `
    <form #testForm="ngForm" id="testForm">
        <input type="text" id="myText" [(ngModel)]="myTextModel" name="myText" #myText="ngModel">
    </form>
    <button (click)="updateMyTextModel()">Update myTextModel</button>
    <div *ngIf="testForm.dirty">testForm diry</div>
    <div *ngIf="testForm.touched">testForm touched</div>
  `,
})
export class App {

  @ViewChild('testForm') test: any;

  updateMyTextModel(){
    this.test.control.markAsTouched();
    this.test.control.markAsDirty();

  }

  constructor() {
    console.log(this.test);
  }
}

@NgModule({
  imports: [ BrowserModule,FormsModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

Plunkr working:

https://plnkr.co/edit/YthHCEp6iTfGPVcNr0JF?p=preview

Tenorio answered 1/12, 2017 at 8:55 Comment(2)
is this.test.control.markAsDirty() still applicable in angular 10?Crellen
@ajgo yes it is. I used thatSeam
M
7

Why not use Reactive forms (FormGroup),

let testForm = new FormGroup({
    myText: new FormControl('initial value')
})

<form [formGroup]="testForm">
    <input type="text" formControlName="myText">
</form>

<button (click)="updateMyTextModel()">Update myTextModel</button>
<div *ngIf="testForm.dirty">testForm diry</div>
<div *ngIf="testForm.touched">testForm touched</div>

In your function, you can use markAsDirty() based on whatever condition you want.

updateMyTextModel(): void {
    this.myTextModel = "updated model value";
    if ( // some condition ) {
        this.testForm.markAsDirty();
    }
}

To set individual form controls as dirty/touched, you can use

this.testForm.get('myText').markAsDirty();
this.testForm.get('myText').markAsTouched();
Mamoun answered 1/12, 2017 at 8:51 Comment(0)
S
3

This should work:

@ViewChild('testForm') testForm;


updateMyTextModel(): void {
    this.myTextModel = "updated model value";
    this.myForm.form.markAsDirty();
}
Santalaceous answered 1/12, 2017 at 8:50 Comment(1)
form.form ... Angular, Angular ^^Yaker
H
1

if you use NgForm form ref through something like this -

@ViewChild('viewChildForm') public viewChildForm: NgForm; and try change form programmatically in .ts file:

  • To set form as invalid: this.viewChildForm.form.setErrors({ 'invalid': true });.

  • To set from as valid: this.viewChildForm.form.setErrors(null);

Hypoglossal answered 11/3, 2019 at 17:22 Comment(1)
To set the form as pristine, this would help: this.viewChildForm.form.markAsPristine();Pleochroism
O
1

If u need to loop through all input fields in a form and mark them touched or dirty :

onSubmit(nameForm)
{
    let inputAryVar = nameForm.form.controls
    for(let keyVar in inputAryVar)
    {
        inputAryVar[keyVar].markAsTouched();
        inputAryVar[keyVar].markAsDirty();
    }
}
Outleap answered 17/9, 2019 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.