Angular 2: iterar sobre controles de forma reactiva

97

Me gustaría markAsDirtytodos los controles dentro de un FormGroup.

Marcos JC Kichel
fuente

Respuestas:

199

Descubrí que Object.keyspuede manejar esto ...

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

Para Angular 8+, use lo siguiente (basado en la respuesta de Miguel Ángel):

    Object.keys(this.form.controls).forEach(key => {
      this.form.controls[key].markAsDirty();
    });
Marcos JC Kichel
fuente
2
Cuando uso esta función en onSubmit, aparece el error Cannot invoke an expression whose type lacks a call signature. Type 'AbstractControl' has no compatible call signatures.¿Alguien sabe por qué?
maidi
1
Object.keys (this.registerForm.controls) .forEach (clave => {this.registerForm.controls [clave] .markAsDirty ();});
Foad
Cuando pruebo Object.keys o incluso el "for in", no obtengo nada. Sin embargo, si consuelo.log (form.controls) puedo VER todos los controles de formulario contenidos en el objeto. Estoy desconcertado.
Jake Shakesworth
Usando Angular 5, markAsDirty () / markAsTouched () no recurre a ningún sub-FormGroups. Rompí el código anterior en una función recursiva y lo llamé en cualquier sub-FormGroups. Funciona mejor con el proyecto actual de interfaz de usuario de material angular en caso de que un usuario nunca toque un elemento requerido, lo llamo cuando el usuario intenta enviar el formulario para marcar alguno en ese momento.
Robert
3
Gracias por leer mi publicación y actualizar su propia respuesta. Los documentos oficiales también están desactualizados, así que tuve que resolver esto imprimiendo cada línea ...
Miguel Ángel
56

Por lo que vale, hay otra forma de hacer esto sin tener que usar la 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
fuente
¿Cómo obtener el índice del bucle?
SVK
1
Para aquellos que usan TSLint, el código funciona, pero TSLint se queja con "las declaraciones for (... in ...) deben filtrarse con una declaración if (forin)".
Yennefer
1
tslint está señalando, una cita de la documentación de JavaScript del for ... en la declaración stackoverflow.com/questions/40770425/…
Egle Kreivyte
41

La respuesta aceptada es correcta para una estructura de forma plana, pero no responde completamente a la pregunta original. Una página web puede requerir FormGroups y FormArrays anidados, y debemos tener esto en cuenta para crear una solución sólida.

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
fuente
será instanceofsiempre trabajar después de haber sido transpiled de imprenta?
el notable
@ the-notable instanceofno es una palabra clave específica de TypeScript ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ) Tampoco lo es el classtipo de datos.
Keenan Diggs
8

Usando la respuesta de @Marcos, creé una función a la que se puede llamar pasando un formGroup como parámetro y marca cada control infantil de formGroup como sucio, solo para que se pueda usar desde más lugares alrededor del código colocándolo dentro de un servicio, por ejemplo.

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

Espero eso ayude ;)

Hugo
fuente
¡Perfecto! Agregado al servicio, junto con funciones similares a clearValidators, untouch, etc. Es posible que desee agregar una verificación recursiva para controles anidados, pero esto funciona por ahora. ¡Gracias!
mc01
6

Parece que la get función ya no funciona para recuperar valores específicos en su formulario en Angular 8, así que así es como lo resolví en función de la respuesta de @Liviu Ilea.

for (const field in this.myForm.controls) { // 'field' is a string
  console.log(this.myForm.controls[field].value);
}
Miguel Angel
fuente
¿Estás seguro? API doc ya tiene el método get para Abstract Control ( angular.io/api/forms/AbstractControl#get ). Todavía no he migrado. Ahora tengo miedo (⊙_ ◎)
Alan Grosz
@AlanGrosz Sí, también lo vi cuando lo estaba reescribiendo, pero incluso al imprimir todas las líneas en la consola no pude encontrar ningún método de obtención en el objeto. Creo que la documentación está atrasada. ¡Buena suerte migrando!
Miguel Ángel
No creo que lo hayan eliminado, obtengo trabajos para mí en Angular 8. También está todavía en la documentación angular.io/api/forms/AbstractControl#get
Laszlo Sarvold
5

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

Foad
fuente
4

Esto es lo que funciona para mi

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
fuente
1

Creo esta función para que sea * Tengo un control con el nombre 'orden' y le paso el índice.

{"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
fuente