Angular 2: itera sobre os controles de forma reativa

93

Eu gostaria de markAsDirtytodos os controles dentro de um FormGroup.

Marcos JC Kichel
fonte

Respostas:

193

Descobri que Object.keyspode lidar com isso ..

    Object.keys(this.form.controls).forEach(key => {
      this.form.get(key).markAsDirty();
    });

Para Angular 8+, use o seguinte (com base na resposta de Michelangelo):

    Object.keys(this.form.controls).forEach(key => {
      this.form.controls[key].markAsDirty();
    });
Marcos JC Kichel
fonte
2
Quando uso essa função no onSubmit, recebo o erro Cannot invoke an expression whose type lacks a call signature. Type 'AbstractControl' has no compatible call signatures.. Alguém sabe por quê?
maidi
1
Object.keys (this.registerForm.controls) .forEach (key => {this.registerForm.controls [key] .markAsDirty ();});
Foad
Quando tento Object.keys ou mesmo o "for in", não recebo nada. No entanto, se eu console.log (form.controls), posso VER todos os vários controles de formulário contidos no objeto. Estou perplexo.
Jake Shakesworth
Usando Angular 5, o markAsDirty () / markAsTouched () não recursa em nenhum subFormGroups. Eu dividi o código acima em uma função recursiva e chamei-a em qualquer subFormGroups. Funciona melhor com o projeto Angular Material UI atual, caso um usuário nunca toque em um elemento necessário, eu o chamo quando o usuário tenta enviar o formulário para marcar algum naquele ponto.
Robert
3
Thnx por ler meu post e atualizar sua própria resposta. Os documentos oficiais também estão desatualizados, então tive que descobrir isso imprimindo todas as linhas ...
Michelangelo
53

Pelo que vale a pena, há outra maneira de fazer isso sem ter que usar a magia Object.keys (...) :

for (const field in this.form.controls) { // 'field' is a string

  const control = this.form.get(field); // 'control' is a FormControl  

}
Liviu Ilea
fonte
como obter o índice do loop?
SVK
1
Para aqueles que usam TSLint, o código funciona, mas o TSLint reclama com "as instruções for (... in ...) devem ser filtradas com uma instrução if (forin)".
Yennefer
1
tslint está apontando, uma citação da documentação JavaScript do for ... in statement stackoverflow.com/questions/40770425/…
Egle Kreivyte
39

A resposta aceita está correta para uma estrutura de formulário plano, mas não responde completamente à pergunta original. Uma página da web pode exigir FormGroups e FormArrays aninhados, e devemos levar isso em consideração para criar uma solução robusta.

public markControlsDirty(group: FormGroup | FormArray): void {
    Object.keys(group.controls).forEach((key: string) => {
        const abstractControl = group.controls[key];

        if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
            this.markControlsDirty(abstractControl);
        } else {
            abstractControl.markAsDirty();
        }
    });
}
Keenan Diggs
fonte
vai instanceofsempre trabalhar depois de ser transpiled por Typescript?
o notável
@ the-notable instanceofnão é uma palavra-chave específica do TypeScript ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ) Nem o classtipo de dados.
Keenan Diggs
6

Parece que a get função não está mais funcionando para recuperar valores específicos em seu formulário no Angular 8, então foi assim que resolvi com base na resposta de @Liviu Ilea.

for (const field in this.myForm.controls) { // 'field' is a string
  console.log(this.myForm.controls[field].value);
}
Michelangelo
fonte
Você tem certeza? A API doc já possui o método get para o Abstract Control ( angular.io/api/forms/AbstractControl#get ). Eu não migrei ainda. Agora estou com medo (⊙_ ◎)
Alan Grosz
@AlanGrosz Sim, também vi isso quando estava reescrevendo, mas mesmo ao imprimir todas as linhas no console, não consegui encontrar nenhum método get no objeto. Acho que a documentação está atrasada. Boa sorte na migração!
Michelangelo de
Não acho que eles tenham removido, consiga trabalhos para mim no Angular 8. Também ainda está na documentação angular.io/api/forms/AbstractControl#get
Laszlo Sarvold
6

Usando a resposta @Marcos criei uma função que pode ser chamada passando um formGroup como parâmetro e marca todos os controles filhos de formGroup como sujos, apenas para torná-lo utilizável de mais lugares ao redor do código colocando-o dentro de um serviço, por exemplo.

public touchAllFormFields(formGroup: FormGroup): void {
    Object.keys(formGroup.controls).forEach((key) => {
        formGroup.get(key).markAsDirty();
    });
}

espero que ajude ;)

Hugo
fonte
Perfeito! Adicionado ao serviço, juntamente com funções semelhantes para clearValidators, untouch, etc. Pode ser necessário adicionar verificação recursiva para controles aninhados, mas isso funciona por enquanto. Obrigado!
mc01
5

    Object.keys( this.registerForm.controls).forEach(key => {
       this.registerForm.controls[key].markAsDirty();
    });

Foad
fonte
3

Isso é o que funciona para mim

private markFormGroupTouched(formGroup: FormGroup) {
  Object.keys(formGroup.controls).forEach((key) => {
    const control = formGroup.controls[key];
    control.markAsDirty();
    if ((control instanceof FormGroup)) {
      this.markFormGroupTouched(control);
    }
  });
}
omyfish
fonte
1

Eu crio esta função para torná-la * Eu tenho um controle com o nome 'pedido' e passo o índice para ele.

{"conditionGroups": [
   {
     "order": null,
     "conditions": []
   }
  ]
}


updateFormData() {
    const control = <FormArray>this.form.controls['conditionGroups'];  
    control.value.map((x,index)=>{
    x.order = index; 
 })
João Marcos Santos Teixeira
fonte