Angular.js configurando programaticamente um campo de formulário como sujo

105

Estou atualizando programaticamente alguns dos campos em meu formulário com um valor e gostaria de definir o estado do campo como $dirty. Fazendo algo como:

$scope.myForm.username.$dirty = true; não parece funcionar.

Existe um método $setPristineque posso usar para redefinir o estado do campo, mas não existe um $setDirtymétodo?

Então, como fazer isso?

Eu vi esta postagem https://groups.google.com/forum/#!topic/angular/NQKGAFlsln4, mas não consigo encontrar o $setDirtymétodo. Estou usando a versão 1.1.5 do Angular.

super9
fonte
pode ser que você só precise definir algum valor (padrão)?
Cherniv
3
O método $ setDirty está documentado aqui: docs.angularjs.org/api/ng.directive:form.FormController
David Lin
2
O parece estar em um nível de formulário. Eu preciso de um $setDirtynível de campo.
super9 de
indo em um limb aqui, mas uma possível, mas bastante hacky, solução para isso seria descobrir qual ouvinte de evento angular usa para vincular a esse tipo de campo e disparar esse ouvinte manualmente imediatamente após a atualização. </uglyHack>
bguiz
Eu estava pensando em alterar programaticamente a classe, mas isso não mudará o estado do campo do formulário da maneira correta, eu teria pensado ...
super9

Respostas:

51

Desde AngularJS 1.3.4 você pode usar $setDirty()em campos ( fonte ). Por exemplo, para cada campo com erro e marcado como obrigatório, você pode fazer o seguinte:

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

No seu caso, $scope.myForm.username.$setViewValue($scope.myForm.username.$viewValue);resolve o problema - torna o formulário e o campo sujos e acrescenta as classes CSS apropriadas.

Para ser sincero, encontrei essa solução em nova postagem no tópico do link da sua pergunta. Funcionou perfeitamente para mim, então estou colocando isso aqui como uma resposta autônoma para torná-la mais fácil de ser encontrada.

EDITAR:

A solução acima funciona melhor para a versão Angular até 1.3.3. A partir de 1.3.4, você deve usar o método API recém-exposto $setDirty()de ngModel.NgModelController.

rmag
fonte
Isso pareceu mudar para mim entre o Angular 1.3.0-beta5 e 1.3.0, onde 1.3.0 mantém o campo $ intocado desde que o $ viewValue não seja alterado. Eu tive que fazer $scope.myForm.myField.$pristine = false; $scope.myForm.myField.$setViewValue(...). Parece que a resposta abaixo informando que field.$setDirty()foi adicionado no Angular 1.3.4 será a melhor solução
Johann
4
Obrigado por sua nota, você salvou meu dia "até 1.3.3. Começando com 1.3.4, você deve usar o método API recém-exposto"
Ahmed Mahmoud
usuário rmag, e o angular 2?
user5260143
17

você terá que definir manualmente $dirtypara truee $pristinepara falsepara o campo. Se quiser que as classes apareçam em sua entrada, você terá que adicionar ng-dirtye remover manualmente as ng-pristineclasses do elemento. Você pode usar $setDirty()no nível do formulário para fazer tudo isso no próprio formulário, mas não nas entradas de formulário, as entradas de formulário não têm atualmente $setDirty()como você mencionou.

Esta resposta pode mudar no futuro à medida que devem ser adicionadas $setDirty()às entradas, parece lógico.

TheSharpieOne
fonte
3
$ setPristine () está no nível do campo de entrada, mas ainda não $ setDirty em 1.2.26 :-(
Sebastian,
10

Se você tiver acesso ao NgModelController (você só pode obter acesso a ele por meio de uma diretiva), poderá chamar

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
fonte
Obrigado! Exatamente o que eu estava procurando.
dreyln
10

Fiz um jsFiddle apenas para você que resolve esse problema. simplesmente defina $ dirty como true, mas com $timeout 0so será executado após o DOM ser carregado.

Encontre aqui: JsFiddle

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

Isto é o que funcionou para mim

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

Uma função auxiliar para fazer o trabalho:

function setDirtyForm(form) {
    angular.forEach(form.$error, function(type) {
        angular.forEach(type, function(field) {
            field.$setDirty();
        });
    });
    return form;
}
Rodolfo Jorge Nemer Nogueira
fonte
Ei, infelizmente eu votei contra isso acidentalmente. Como faço para reverter. Então me dizendo que eu não posso fazer isso sem que a resposta seja editada ..
smk
Isso funciona bem; upvoting como verificação de 'form. $ error' garante que não estamos 'sujando' campos que o usuário não tocou, mas que são válidos.
Sam T
Obrigado! Solução fácil e simples. Pode não ser o mais rápido, mas não faz nada pesado, então realmente não importa. Bom trabalho!
jwanglof de
4

Angular 2

Para quem quer fazer o mesmo no Angular 2, é muito semelhante, exceto pelo controle do formulário

<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
fonte
3

Uma pequena nota adicional à resposta de @rmag. Se você tiver campos vazios, mas obrigatórios que deseja tornar sujos, use isto:

$scope.myForm.username.$setViewValue($scope.myForm.username.$viewValue !== undefined 
    ? $scope.myForm.username.$viewValue : '');
Fran Arant
fonte
Esta é a resposta que finalmente me ajudou!
Kirk Liemohn
-1

Não sei exatamente por que você está tentando marcar os campos como incorretos, mas me encontrei em uma situação semelhante porque queria que erros de validação aparecessem quando alguém tentasse enviar um formulário inválido. Acabei usando jQuery para remover as .ng-pristinetags de classe e adicionar .ng-dirtytags de classe aos campos apropriados. Por exemplo:

$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
fonte
5
Dado que já estamos usando AngularJS, uma solução jQuery parece um exagero. Muitas pessoas preferem não usar jQuery com AngularJS, por exemplo.
StevenClontz