Como encontrar os controles inválidos na forma reativa angular 4


92

Eu tenho uma forma reativa em Angular como abaixo:

this.AddCustomerForm = this.formBuilder.group({
    Firstname: ['', Validators.required],
    Lastname: ['', Validators.required],
    Email: ['', Validators.required, Validators.pattern(this.EMAIL_REGEX)],
    Picture: [''],
    Username: ['', Validators.required],
    Password: ['', Validators.required],
    Address: ['', Validators.required],
    Postcode: ['', Validators.required],
    City: ['', Validators.required],
    Country: ['', Validators.required]
});

createCustomer(currentCustomer: Customer) 
{
    if (!this.AddCustomerForm.valid)
    {
        //some app logic
    }
}

this.AddCustomerForm.valid retorna falso, mas tudo parece bom.

Eu tentei descobrir com a verificação da propriedade de status na coleção de controles. Mas eu me pergunto se existe uma maneira de localizar os inválidos e exibi-los ao usuário?


Se você deseja apenas exibir os campos com erro, pode usar css para destacar ou colorir os campos inválidos. Cada campo inválido tem uma classe "ng-invalid" anexada em sua lista de classes
— LookForAngular

Respostas:


176

Você pode simplesmente iterar em cada controle e verificar o status:

    public findInvalidControls() {
        const invalid = [];
        const controls = this.AddCustomerForm.controls;
        for (const name in controls) {
            if (controls[name].invalid) {
                invalid.push(name);
            }
        }
        return invalid;
    }

1
obrigado por isso mas tentei fazer isso e mesmo isso não retorna nada meu formulário ainda é inválido, isso é estranho. Quer dizer, este código parece bom, mas não faz sentido porque form.valid retorna falso
— sa_

o que findInvalidControls()você retorna?
— Max Koretskyi

1
não retorna nada, inválido está vazio. Eu verifiquei um por um na tela de visualização de depuração, todos os controles são válidos, mas this.AddCustomerForm.valid ainda retorna falso.
— sa_

Eu acho que descobri. há um campo de e-mail e uma expressão regular, mas de alguma forma o status do controle é PENDENTE e pode ser a causa
— sa_

7
@ AngularInDepth.com - se um dos controles for um grupo de formulários, sua função retornará o grupo de formulários inválido e não o controle de formulário específico que é inválido
— john Smith

36

Acabei de lutar contra este problema: cada campo do formulário é válido, mas ainda assim o próprio formulário é inválido.

Acontece que eu tinha definido 'Validator.required' em um FormArray onde os controles são adicionados / removidos dinamicamente. Portanto, mesmo que o FormArray estivesse vazio, ele ainda era necessário e, portanto, o formulário sempre era inválido, mesmo se todos os controles visíveis fossem preenchidos corretamente.

Eu não encontrei a parte inválida do formulário, porque minha função 'findInvalidControls' verificou apenas FormControl's e não FormGroup / FormArray. Então eu atualizei um pouco:

/* 
   Returns an array of invalid control/group names, or a zero-length array if 
   no invalid controls/groups where found 
*/
public findInvalidControlsRecursive(formToInvestigate:FormGroup|FormArray):string[] {
    var invalidControls:string[] = [];
    let recursiveFunc = (form:FormGroup|FormArray) => {
      Object.keys(form.controls).forEach(field => { 
        const control = form.get(field);
        if (control.invalid) invalidControls.push(field);
        if (control instanceof FormGroup) {
          recursiveFunc(control);
        } else if (control instanceof FormArray) {
          recursiveFunc(control);
        }        
      });
    }
    recursiveFunc(formToInvestigate);
    return invalidControls;
  }

3
Resposta incrivelmente útil. Muito obrigado
— Mikki

1
Concordo, uma resposta muito útil.
— nenea

24

Um controle Angular inválido possui a classe CSS chamada 'ng-invalid' .

Em DevTools no Chrome, selecione a guia Console.

No prompt do console, digite o comando:

document.getElementsByClassName('ng-invalid')

A saída deve ser semelhante a esta: insira a descrição da imagem aqui

Nesse caso, o texto sublinhado é para o controle do formulário listen-address. E o texto circulado: .ng-invalidindica que o controle é inválido.

Nota: Testado em cromo


2
esta parece ser a forma mais direta de responder à pergunta.
— ckapilla

2
Você me salvou de enlouquecer, se eu pudesse
— pagar

3

Os formulários e todos os seus controles estendem a classe angular AbstractControl. Cada implementação possui um acessador para os erros de validação.

let errors = this.AddCustomerForm.errors
// errors is an instance of ValidatorErrors

A documentação da API contém todas as referências https://angular.io/api/forms/AbstractControl

Editar

Achei que o acessador de erro funcionasse dessa maneira, no entanto, este link para o github mostra que há algumas outras pessoas que pensaram o mesmo que eu https://github.com/angular/angular/issues/11530

Em qualquer caso, usando o acessador de controles, você pode iterar sobre todos os formControls em seu formulário.

Object.keys(this.AddCustomerForm.controls)
    .forEach( control => {
        //check each control here
        // if the child is a formGroup or a formArray
        // you may cast it and check it's subcontrols too
     })

1
isso retorna nulo mesmo que haja controles vazios
— sa_

1
Ele deve retornar nulo quando não houver erros. Você pode postar seu modelo?
— LookForAngular de

Sim, isso não vai funcionar, as diferentes validações definidas em cada controle de formulário, esses controles de cada formulário contêm seus erros, o formulário não. Você precisa iterar os controles como o Maximus deu a resposta.
— AJT82 de

Posso acessar erros para cada contorls individual como this.form.controls ['Email'].
— Errors

@ AJT_82 de fato, o próprio formulário pode mostrar erros se um validador tiver sido definido para o formGroup (verifique os documentos sobre validação de campo cruzado, o que faz sentido validar no grupo e não no controle)
— LookForAngular

3

Agora, no angular 9, você pode usar o método markAllAsTouched () para mostrar os validadores de controles inválidos:

this.AddCustomerForm.markAllAsTouched();

Vou dar +1, pois me ajudou a descobrir o que eu precisava saber --- que é mostrar mensagens de validação quando o usuário não necessariamente tocou nas entradas.
— Sean Halls

1

Se você não tiver muitos campos no formulário, pode simplesmente F12 e passar o mouse sobre o controle, você poderá ver o pop-up com os valores pristine / Touch / valid do campo- "# fieldname.form-control.ng- untouched.ng-invalid ".


1

Acho que você deve tentar usar this.form.updateValueAndValidity()ou tentar executar o mesmo método em cada um dos controles.


1

tente isso

 findInvalidControls(f: FormGroup) {
    const invalid = [];
    const controls = f.controls;
    for (const name in controls) {
      if (controls[name].invalid) {
        invalid.push(name);
      }
    }
    return invalid;
  }

1

Isso irá registrar todos os nomes dos controles 😊

for (let el in this.ReactiveForm.controls) {
      if (this.ReactiveForm.controls[el].errors) {
        console.log(el)
      }
 }          

você pode fazer uma matriz ou string com isso e exibir para o usuário


0

Tomei a liberdade de melhorar o código do AngularInDepth.com , de modo que ele também procure entradas inválidas em formulários aninhados de maneira recursiva. Seja aninhado por FormArray-s ou FormGroup-s. Basta inserir o formGroup de nível superior e ele retornará todos os FormControls que são inválidos.

Você pode possivelmente ignorar algumas das verificações do tipo "instanceof", se separar a verificação do FormControl e a adição à funcionalidade de array inválido em uma função separada. Isso faria com que a função parecesse muito mais limpa, mas eu precisava de uma opção de função única e global para obter um array simples de todos os formControls inválidos e esta é a solução!

findInvalidControls( _input: AbstractControl, _invalidControls: AbstractControl[] ): AbstractControl[] {
    if ( ! _invalidControls ) _invalidControls = [];
    if ( _input instanceof FormControl  ) {
        if ( _input.invalid ) _invalidControls.push( _input );
        return _invalidControls;
    }

    if ( ! (_input instanceof FormArray) && ! (_input instanceof FormGroup) ) return _invalidControls;

    const controls = _input.controls;
    for (const name in controls) {
        let control = controls[name];
        switch( control.constructor.name )
        {
            case 'AbstractControl':
            case 'FormControl':
                if (control.invalid) _invalidControls.push( control );
                break;

            case 'FormArray':
                (<FormArray> control ).controls.forEach( _control => _invalidControls = findInvalidControls( _control, _invalidControls ) );
                break;

            case 'FormGroup':
                _invalidControls = findInvalidControls( control, _invalidControls );
                break;
        }
    }

    return _invalidControls;
}

Apenas para aqueles que precisam, para que não tenham que codificar sozinhos.

Editar # 1

Foi solicitado que ele também retornasse FormArray-s e FormGroups inválidos, então se você também precisar disso, use este código

findInvalidControls( _input: AbstractControl, _invalidControls: AbstractControl[] ): AbstractControl[] {
    if ( ! _invalidControls ) _invalidControls = [];
    if ( _input instanceof FormControl  ) {
        if ( _input.invalid ) _invalidControls.push( _input );
        return _invalidControls;
    }

    if ( ! (_input instanceof FormArray) && ! (_input instanceof FormGroup) ) return _invalidControls;

    const controls = _input.controls;
    for (const name in controls) {
        let control = controls[name];
        if (control.invalid) _invalidControls.push( control );
        switch( control.constructor.name )
        {    
            case 'FormArray':
                (<FormArray> control ).controls.forEach( _control => _invalidControls = findInvalidControls( _control, _invalidControls ) );
                break;

            case 'FormGroup':
                _invalidControls = findInvalidControls( control, _invalidControls );
                break;
        }
    }

    return _invalidControls;
}

1
Eu tentei, mas não encontrou nenhum FormGroup ou FormArray inválido ... apenas FormControl inválido. Eu cometi o mesmo erro ... veja minha resposta.
— Jette

Melhorei minha resposta para se adequar ao seu caso de uso.
— Karl Johan Vallner

0

você pode registrar o valor do formulário console.log(this.addCustomerForm.value), ele consolará todos os valores do controle e os campos nulos ou "" (vazio) indicam controles inválidos


0

Se quiser verificar se o formulário é válido ou não e não quiser fazer nenhuma alteração no código, você pode tentar executar o seguinte comando no console da ferramenta de desenvolvedor do Chrome. Certifique-se de que seu aplicativo angular esteja exibindo o componente que hospeda o formulário em questão.

ng.probe(document.querySelector("app-your-component-selector-name")).componentInstance;

Não se esqueça de substituir o nome do seletor de componente no comando acima.

Este comando irá listar todas as variáveis ​​de seu componente, incluindo AddCustomerForm. Agora, se você expandir isso, verá uma lista de todos os seus controles. Você pode então expandir cada controle para verificar se ele é válido ou não.


-1

Verifique o valor de controle de formulário vazio ou nulo na página html

Valor dos controles do formulário: {{formname.value | json}}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.