validar reactivos formularios formulario con campos angular angular2-forms

reactivos - validar campos con angular 2



Formas reactivas angulares 2 activan la validación en el envío (6)

Encontré algo que podría ser de interés:

Al enviar, establezco submitAttempt = true y lo puse en el div donde debería realizarse la validación:

nickname.touched || nickname.dirty || (nickname.untouched && submitAttempt)

significado: si no se ha tocado y tratamos de enviarlo, se muestra el error.

¿Existe alguna forma de que todos los validadores de formas reactivas puedan activarse al enviarse y no solo por los eventos "sucios" y "táctiles"?

El motivo de esto es que tenemos formularios muy grandes que no indican si un campo es requerido o no, y el usuario puede perder parte del control requerido, por lo que al enviar, se espera que todos los campos no válidos se omitan por el usuario final se mostrará.

He intentado marcar el formulario como "tocado" usando el

FormGroup.markAsTouched(true);

funcionó, así que también intenté marcarlo como "sucio"

FormGroup.markAsDirty(true);

pero el css de la clase sigue siendo "ng-pristine",

¿Hay alguna forma de activarlo manualmente desde el componente, traté de buscarlo sin éxito, gracias de antemano!

ACTUALIZAR

Ya lo puse en funcionamiento mediante la iteración de FormGroup.controls y lo marqué como "sucio", pero hay una forma "estándar" de hacerlo.


Esto se puede lograr a través de markAsTouched() :

Object.keys(this.myFormGroup.controls).map((controlName) => { this.myFormGroup.get(controlName).markAsTouched({onlySelf: true}); });

Esto no se encontró en los documentos de AbstractControl , pero está en el código fuente .


Esto se puede lograr con el ejemplo presentado here , donde puede hacer uso de la directiva NgForm :

<form [formGroup]="heroForm" #formDir="ngForm">

y luego, en sus mensajes de validación, simplemente verifique si se ha enviado el formulario:

<small *ngIf="heroForm.hasError(''required'', ''formCtrlName'') && formDir.submitted"> Required! </small>


Hay múltiples formas de resolver el problema. La respuesta de @ Splaktar no funcionará si tiene grupos de formularios anidados. Entonces, aquí está la solución que funcionará con grupos de formularios anidados.

Solución 1 : Iterar a través de todos los grupos de formularios y controles de formulario y tocarlos programáticamente para activar validaciones.

Código de plantilla:

<form [formGroup]="myForm" (ngSubmit)="onSubmit()" novalidate> ... <button type="submit" class="btn btn-success">Save</button> </form>

código de component.ts:

onSubmit() { if (this.myForm.valid) { // save data } else { this.validateAllFields(this.myForm); } } validateAllFields(formGroup: FormGroup) { Object.keys(formGroup.controls).forEach(field => { const control = formGroup.get(field); if (control instanceof FormControl) { control.markAsTouched({ onlySelf: true }); } else if (control instanceof FormGroup) { this.validateAllFields(control); } }); }

Solución 2 : use una variable para verificar si el formulario ha sido enviado o no. FYI: el campo enviado para el ngForm se está probando actualmente y se incluirá en futuras versiones de Angular. Así que no habrá necesidad de crear tu propia variable.

código de component.ts

private formSubmitAttempt: boolean; onSubmit() { this.formSubmitAttempt = true; if (this.myForm.valid) { console.log(''form submitted''); } }

Código de plantilla:

<form [formGroup]="myForm" (ngSubmit)="onSubmit()" novalidate> <div class="form-group"> <label class="center-block"> Name: <input class="form-control" formControlName="name"> </label> <div class="alert alert-danger" *ngIf="myForm.get(''name'').hasError(''required'') && formSubmitAttempt"> Name is required </div> ... </form>


Mi aplicación tiene muchos formularios y entradas, por lo que creé varios componentes de formularios personalizados (para entradas de texto normales, entradas de área de texto, selecciones, casillas de verificación, etc.) para que no tenga que repetir HTML / CSS detallado y lógica de UI de validación de formularios. sobre el lugar.

Mi componente de formulario base personalizado busca su FormGroupDirective alojamiento y utiliza su propiedad submitted además de sus estados de FormControl ( valid , touched , etc.) para decidir qué estado de validación y mensaje (si corresponde) debe mostrarse en la interfaz de usuario.

Esta solución

  • no requiere atravesar los controles del formulario y modificar su estado
  • no requiere agregar alguna propiedad adicional submitted a cada control
  • no requiere ningún manejo de validación de formulario adicional en los métodos ngSubmit -binded onSubmit
  • no combina formas controladas por plantillas con formas reactivas

form-base.component:

import {Host, Input, OnInit, SkipSelf} from ''@angular/core''; import {FormControl, FormGroupDirective} from ''@angular/forms''; export abstract class FormBaseComponent implements OnInit { @Input() id: string; @Input() label: string; formControl: FormControl; constructor(@Host() @SkipSelf() private formControlHost: FormGroupDirective) { } ngOnInit() { const form = this.formControlHost.form; this.formControl = <FormControl>form.controls[this.id]; if (!this.formControl) { throw new Error(''FormControl /''' + this.id + ''/' needs to be defined''); } } get errorMessage(): string { // TODO return error message based on ''this.formControl.errors'' return null; } get showInputValid(): boolean { return this.formControl.valid && (this.formControl.touched || this.formControlHost.submitted); } get showInputInvalid(): boolean { return this.formControl.invalid && (this.formControl.touched || this.formControlHost.submitted); } }

form-text.component:

import {Component} from ''@angular/core''; import {FormBaseComponent} from ''../form-base.component''; @Component({ selector: ''yourappprefix-form-text'', templateUrl: ''./form-text.component.html'' }) export class FormTextComponent extends FormBaseComponent { }

form-text.component.html:

<label class="x_label" for="{{id}}">{{label}}</label> <div class="x_input-container" [class.x_input--valid]="showInputValid" [class.x_input--invalid]="showInputInvalid"> <input class="x_input" id="{{id}}" type="text" [formControl]="formControl"> <span class="x_input--error-message" *ngIf="errorMessage">{{errorMessage}}</span> </div>

Uso:

<form [formGroup]="form" novalidate> <yourappprefix-form-text id="someField" label="Some Field"></yourappprefix-form-text> </form>


Regresando después de algunos meses, comparto aquí la versión mejorada basada en todos los comentarios, solo para el registro:

markAsTouched(group: FormGroup | FormArray) { Object.keys(group.controls).map((field) => { const control = group.get(field); if (control instanceof FormControl) { control.markAsTouched({ onlySelf: true }); } else if (control instanceof FormGroup) { this.markAsTouched(control); } }); }

Espero que sea de utilidad!