[angularjs] Angular.js programmatically setting a form field to dirty

I am programmatically updating some of the fields on my form with a value and I would like to set the field state to $dirty. Doing something like:

$scope.myForm.username.$dirty = true; doesn't seem to work.

There is a method $setPristine that I can use to reset the state of the field but there isn't a $setDirty method?

So how does one go about doing this?

I saw this post https://groups.google.com/forum/#!topic/angular/NQKGAFlsln4 but I can't seem to find the $setDirty method. I am using Angular version 1.1.5.

This question is related to angularjs

The answer is


This is what worked for me

$scope.form_name.field_name.$setDirty()

You can use $setDirty(); method. See documentation https://docs.angularjs.org/api/ng/type/form.FormController

Example:

$scope.myForm.$setDirty();

you will have to manually set $dirty to true and $pristine to false for the field. If you want the classes to appear on your input, then you will have to manually add ng-dirty and remove ng-pristine classes from the element. You can use $setDirty() on the form level to do all of this on the form itself, but not the form inputs, form inputs do not currently have $setDirty() as you mentioned.

This answer may change in the future as they should add $setDirty() to inputs, seems logical.


If you have access to the NgModelController (you can only get access to it from a directive) then you can call

ngModel.$setViewValue("your new view value");
// or to keep the view value the same and just change it to dirty
ngModel.$setViewValue(ngModel.$viewValue);

A helper function to do the job:

function setDirtyForm(form) {
    angular.forEach(form.$error, function(type) {
        angular.forEach(type, function(field) {
            field.$setDirty();
        });
    });
    return form;
}

I'm not sure exactly why you're trying to mark the fields dirty, but I found myself in a similar situation because I wanted validation errors to show up when somebody attempted to submit an invalid form. I ended up using jQuery to remove the .ng-pristine class tags and add .ng-dirty class tags to the appropriate fields. For example:

$scope.submit = function() {
    // `formName` is the value of the `name` attribute on your `form` tag
    if (this.formName.$invalid)
    {
        $('.ng-invalid:not("form")').each(function() {
            $(this).removeClass('ng-pristine').addClass('ng-dirty');
        });
        // the form element itself is index zero, so the first input is typically at index 1
        $('.ng-invalid')[1].focus();
    }
}

In your case, $scope.myForm.username.$setViewValue($scope.myForm.username.$viewValue); does the trick - it makes both the form and the field dirty, and appends appropriate CSS classes.

Just to be honest, I found this solution in new post in the topic from the link from your question. It worked perfectly for me, so I am putting this here as a standalone answer to make it easier to be found.

EDIT:

Above solution works best for Angular version up to 1.3.3. Starting with 1.3.4 you should use newly exposed API method $setDirty() from ngModel.NgModelController.


Angular 2

For anyone looking to do the same in Angular 2 it is very similar apart from getting a hold of the form

<form role="form" [ngFormModel]="myFormModel" (ngSubmit)="onSubmit()" #myForm="ngForm">
<div class="form-group">
    <label for="name">Name</label>
    <input autofocus type="text" ngControl="usename" #name="ngForm" class="form-control" id="name" placeholder="Name">
    <div [hidden]="name.valid || name.pristine" class="alert alert-danger">
        Name is required
    </div>
</div>
</form>
<button type="submit" class="btn btn-primary" (click)="myForm.ngSubmit.emit()">Add</button>

import { Component, } from '@angular/core';
import { FormBuilder, Validators } from '@angular/common';

@Component({
    selector: 'my-example-form',
    templateUrl: 'app/my-example-form.component.html',
    directives: []
})
export class MyFormComponent {
    myFormModel: any;

    constructor(private _formBuilder: FormBuilder) {
        this.myFormModel = this._formBuilder.group({
            'username': ['', Validators.required],
            'password': ['', Validators.required]
        });
    }

    onSubmit() {
        this.myFormModel.markAsDirty();
        for (let control in this.myFormModel.controls) {
            this.myFormModel.controls[control].markAsDirty();
        };

        if (this.myFormModel.dirty && this.myFormModel.valid) {
            // My submit logic
        }
    }
}

Made a jsFiddle just for you that solves this issue. simply set $dirty to true, but with a $timeout 0 so it runs after DOM was loaded.

Find it here: JsFiddle

$timeout(function () {
  $scope.form.uName.$dirty = true;
}, 0);

Small additional note to @rmag's answer. If you have empty but required fields that you want to make dirty use this:

$scope.myForm.username.$setViewValue($scope.myForm.username.$viewValue !== undefined 
    ? $scope.myForm.username.$viewValue : '');