Angular.js configurando programáticamente un campo de formulario como sucio

105

Estoy actualizando programáticamente algunos de los campos en mi formulario con un valor y me gustaría establecer el estado del campo en $dirty . Haciendo algo como:

$scope.myForm.username.$dirty = true; no parece funcionar.

Hay un método $setPristineque puedo usar para restablecer el estado del campo, pero no hay un$setDirty método?

Entonces, ¿cómo se hace esto?

Vi esta publicación https://groups.google.com/forum/#!topic/angular/NQKGAFlsln4 pero parece que no puedo encontrar el $setDirtymétodo. Estoy usando la versión 1.1.5 de Angular.

super9
fuente
¿Puede ser que solo necesite establecer algún valor (predeterminado)?
Cherniv
3
El método $ setDirty está documentado aquí: docs.angularjs.org/api/ng.directive:form.FormController
David Lin
2
Parece estar en un nivel de formulario. Necesito una $setDirtya nivel de campo.
super9
yendo a una extremidad aquí, pero una solución posible, pero bastante hacky, para esto sería averiguar qué oyente de eventos usa angular para unirse a ese tipo de campo, y disparar ese oyente manualmente inmediatamente después de la actualización. </uglyHack>
bguiz
Estaba pensando en cambiar programáticamente la clase, pero no cambiará el estado del campo de formulario de la manera correcta que hubiera pensado ...
super9

Respuestas:

51

Desde AngularJS 1.3.4 puede usar $setDirty()en campos ( fuente ). Por ejemplo, para cada campo con error y marcado como obligatorio, puede hacer lo siguiente:

angular.forEach($scope.form.$error.required, function(field) {
    field.$setDirty();
});
Mateusz Rasiński
fuente
87

En tu caso, $scope.myForm.username.$setViewValue($scope.myForm.username.$viewValue); funciona el truco: ensucia tanto el formulario como el campo, y agrega las clases CSS apropiadas.

Para ser honesto, encontré esta solución en una nueva publicación en el tema del enlace de su pregunta. Funcionó perfectamente para mí, así que pongo esto aquí como una respuesta independiente para que sea más fácil de encontrar.

EDITAR:

La solución anterior funciona mejor para la versión Angular hasta 1.3.3. A partir de 1.3.4, debe usar el método API recién expuesto $setDirty()de ngModel.NgModelController.

rmag
fuente
Esto pareció cambiar para mí entre Angular 1.3.0-beta5 y 1.3.0, donde 1.3.0 mantiene el campo $ prístino siempre que $ viewValue no cambie. Tenía que hacer $scope.myForm.myField.$pristine = false; $scope.myForm.myField.$setViewValue(...). Parece que la respuesta a continuación que indica que field.$setDirty()se agregó en Angular 1.3.4 será la mejor solución
Johann
4
Gracias por tu nota, me salvaste el día "hasta 1.3.3. A partir de 1.3.4 deberías usar el método API recién expuesto"
Ahmed Mahmoud
user rmag, ¿y angular 2?
user5260143
17

tendrá que configurar manualmente $dirtya truey $pristinea falsepara el campo. Si desea que las clases aparezcan en su entrada, tendrá que agregar ng-dirtyy eliminar ng-pristineclases manualmente del elemento. Puede usar $setDirty()en el nivel de formulario para hacer todo esto en el formulario en sí, pero no en las entradas de formulario, las entradas de formulario no tienen actualmente $setDirty()como mencionó.

Esta respuesta puede cambiar en el futuro ya que deberían agregarse $setDirty()a las entradas, parece lógico.

TheSharpieOne
fuente
3
$ setPristine () está en el nivel de campo de entrada pero aún no hay $ setDirty en 1.2.26 :-(
Sebastian
10

Si tiene acceso al NgModelController (solo puede acceder a él desde una directiva), puede llamar

ngModel.$setViewValue("your new view value");
// or to keep the view value the same and just change it to dirty
ngModel.$setViewValue(ngModel.$viewValue);
Marshall Brekka
fuente
¡Gracias! Exactamente lo que estaba buscando.
dreyln
10

Hice un jsFiddle solo para usted que resuelve este problema. simplemente establezca $ sucio en verdadero, pero con un $timeout 0modo que se ejecuta después de que se cargó DOM.

Encuéntrelo aquí: JsFiddle

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

Esto es lo que funcionó para mi

$scope.form_name.field_name.$setDirty()
Shakirthow
fuente
5

Una función auxiliar para hacer el trabajo:

function setDirtyForm(form) {
    angular.forEach(form.$error, function(type) {
        angular.forEach(type, function(field) {
            field.$setDirty();
        });
    });
    return form;
}
Rodolfo Jorge Nemer Nogueira
fuente
Oye, desafortunadamente, accidentalmente voté en contra. ¿Cómo lo revierto? Entonces, diciéndome que no puedo hacer esto sin que se edite la respuesta ..
smk
Esto funciona bien; la votación positiva como verificación de 'formulario. $ error' asegura que no estamos 'ensuciando' campos que el usuario no tocó, pero que son válidos.
Sam T
¡Gracias! Solución fácil y sencilla. Puede que no sea el más rápido, pero no hace nada pesado, por lo que realmente no importa. ¡Buen trabajo!
jwanglof
4

Angular 2

Para cualquiera que busque hacer lo mismo en Angular 2, es muy similar, además de obtener el formulario

<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
        }
    }
}
edqwerty
fuente
3

Pequeña nota adicional a la respuesta de @ rmag. Si tiene campos vacíos pero obligatorios que desea ensuciar, use esto:

$scope.myForm.username.$setViewValue($scope.myForm.username.$viewValue !== undefined 
    ? $scope.myForm.username.$viewValue : '');
Fran Arant
fuente
¡Esta es la respuesta que finalmente me ayudó!
Kirk Liemohn
-1

No estoy seguro de por qué está intentando marcar los campos como sucios, pero me encontré en una situación similar porque quería que aparecieran errores de validación cuando alguien intentaba enviar un formulario no válido. Terminé usando jQuery para eliminar las .ng-pristineetiquetas de clase y agregar .ng-dirtyetiquetas de clase a los campos correspondientes. Por ejemplo:

$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();
    }
}
Ben Harold
fuente
5
Dado que ya estamos usando AngularJS, una solución de jQuery parece excesiva. Mucha gente prefiere no usar jQuery con AngularJS, por ejemplo.
StevenClontz