How to check for changes in form controls using Angular5
Solution 1
try using valueChanges
along with Array.some()
functions
hasError: boolean = false;
constructor(private elRef: ElementRef,
private formBuilder: FormBuilder,
private cdRef: ChangeDetectorRef) {
this.createForm();
// listen to all changes on the form
this.contratoForm.valueChanges.subscribe(_ => {
const controllersToCheck = [
'txtCodigoContrato',
'txtCodigoContrato2',
'txtContrato'
];
this.hasError = controllersToCheck.some(ctrlName => {
let ctrl = this.contratoForm.get(ctrlName);
return (ctrl.dirty || ctrl.touched) &&
(ctrl.hasError('required') || ctrl.hasError('hasWhites'));
});
});
}
(checking !ctrl.valid
is redundant because if controller has an error, then it is invalid)
HTML:
<div *ngIf="hasError">
<span>check the fields in red, they are required</span>
</div>
UPDATE
As stated here
You can also listen to {@link AbstractControl#statusChanges statusChanges} to be notified when the validation status is re-calculated.
I think it will suit your case more, so try to subscribe to statusChanges
event (instead of valueChanges
):
this.contratoForm.statusChanges.subscribe( ..........
UPDATE 2
use a function in your HTML:
<div *ngIf="hasErrors()">
<span>check the fields in red, they are required</span>
</div>
add this function to your component ts file:
hasErrors() {
const controllersToCheck = [
'txtCodigoContrato',
'txtCodigoContrato2',
'txtContrato'
];
return controllersToCheck.some(ctrlName => {
let ctrl = this.contratoForm.get(ctrlName);
return (ctrl.dirty || ctrl.touched) &&
(ctrl.hasError('required') || ctrl.hasError('hasWhites'));
});
}
I created a STACKBLITZ
if you add new controllers with the same validation logic, just add their control names to controllersToCheck
array
Solution 2
You can do something like
this.contratoForm.valueChanges.subscribe(value = > //do something)
If you want you can add a map function before to get just the values from the form you care about that are changing
this.contratoForm.valueChanges
.map(values => values.txtCodigoContrato)
.subscribe(txtCodigoContrato = > //do something)
ararb78
I like sports, but not from an armchair. I like the world of work schedule programming, the rest of the day I dedicate to cultivating my health and mind. I respect the environment, very aware of ecology and respect for animals.
Updated on June 15, 2022Comments
-
ararb78 almost 2 years
Im using reactive forms, I have multiple inputs, I want display a single error for de three inputs, the validatons are; fields are required and blank spaces should not be entered.
component.html:
<form [formGroup]="contratoForm" class="campo-form"> <div class="campoFormulario"> <label class="etiquetaFormulario" for="txtCodigoContrato">Código contrato</label> <div style="display:inline-block; position: relative;" class="control"> <input [formControl]="txtCodigoContrato" type="text" id="txtCodigoContrato" name="txtCodigoContrato" class="cajaTexto ancho80" /> <span>/</span> </div> <div style="display:inline-block; position: relative;" class="control"> <input [formControl]="txtCodigoContrato2" type="text" id="txtCodigoContrato2" name="txtCodigoContrato2" class="cajaTexto ancho80" /> </div> </div> <div class="campoFormulario"> <label class="etiquetaFormulario" for="txtContrato">Contrato</label> <div style="display:inline-block; position: relative;" class="control"> <input [formControl]="txtContrato" type="text" id="txtContrato" name="txtContrato" class="cajaTexto ancho350" /> </div> </div> <div *ngIf="((!txtCodigoContrato.valid && (txtCodigoContrato.dirty || txtCodigoContrato.touched)) && (txtCodigoContrato.hasError('required') || txtCodigoContrato.hasError('hasWhites'))) || ((!txtCodigoContrato2.valid && (txtCodigoContrato2.dirty || txtCodigoContrato2.touched)) && (txtCodigoContrato2.hasError('required') || txtCodigoContrato2.hasError('hasWhites'))) || ((!txtContrato.valid && (txtContrato.dirty || txtContrato.touched)) && (txtContrato.hasError('required') || txtContrato.hasError('hasWhites'))) "> <span>check the fields in red, they are required</span> </div> <div class="buttons"> <button class="btn btn-primary boton" type="button" style="float:right;" (click)="onCloseLink()"> <span class="glyphicon glyphicon-off"></span> Cancel </button> <button class="btn btn-primary boton" type="button" style="float:right;" (click)="limpiar()"> <span class="glyphicon glyphicon-trash"></span> Clean </button> <button type="submit" [disabled]="!contratoForm.valid" class="btn btn-primary boton" style="float:right;" (click)="onClick()"> <span class="glyphicon glyphicon-floppy-disk"></span> Save </button> </div> </form>
component.ts:
import { Component, HostBinding, OnDestroy, OnInit, Input, Output, EventEmitter, ElementRef, NgModule, ViewChild, ChangeDetectorRef } from '@angular/core'; import { Validators, FormBuilder, FormControl, FormGroup, AbstractControl} from '@angular/forms'; import { AfterViewChecked } from '@angular/core/src/metadata/lifecycle_hooks'; @Component({ selector: 'app-formulario-contrato', templateUrl: './contrato.component.html', styleUrls: ['./contrato.component.css'] }) export class FormularioContratoComponent { contratoForm: FormGroup; constructor(private elRef: ElementRef, private formBuilder: FormBuilder, private cdRef: ChangeDetectorRef) { this.createForm(); } txtCodigoContrato = new FormControl('', [ Validators.required ,this.hasNotWhites ]); txtCodigoContrato2 = new FormControl('', [ Validators.required , this.hasNotWhites ]); txtContrato = new FormControl('', [ Validators.required , this.hasNotWhites ]); createForm() { this.contratoForm = this.formBuilder.group({ txtCodigoContrato: this.txtCodigoContrato ,txtCodigoContrato2: this.txtCodigoContrato2 ,txtContrato: this.txtContrato }); } hasNotWhites(fieldControl: FormControl) { if (fieldControl.value.trim() != '') { return null } else { return { hasWhites: true }; } } ngAfterViewChecked() { this.cdRef.detectChanges(); } limpiar() { } onClick() { return null; }
component.css:
/* some stuff...*/ :host /deep/ .control input.ng-invalid.ng-touched { border-color: #ff8080; }
The validations work correctly, that is, they jump when the field stays empty or when I enter blank spaces. My problem is that I have to add more form controls and the if it contains the message can be made illegible:
<div *ngIf="((!txtCodigoContrato.valid && (txtCodigoContrato.dirty || txtCodigoContrato.touched)) && (txtCodigoContrato.hasError('required') || txtCodigoContrato.hasError('hasWhites'))) || ((!txtCodigoContrato2.valid && (txtCodigoContrato2.dirty || txtCodigoContrato2.touched)) && (txtCodigoContrato2.hasError('required') || txtCodigoContrato2.hasError('hasWhites'))) || ((!txtContrato.valid && (txtContrato.dirty || txtContrato.touched)) && (txtContrato.hasError('required') || txtContrato.hasError('hasWhites'))) ">
Is there any way to control these values by typescript, that is, each time a value in the control changes it is controlled by a function in typeScript that returns true or false and if only ask for the value of that function in my div?
-
ararb78 over 6 yearsthis works but only jumps when I make a change in the input. I need to also jump when I just move with the cursor from one input to another without typing anything
-
-
ararb78 over 6 yearsIt works but only jumps when I make a change in the input, I need to jump when I just move with the cursor from one input to another without typing anything
-
Andriy over 6 yearstry to subscribe to
statusChanges
event instead ofvalueChanges
, see my updated answer -
ararb78 over 6 yearsI changed it to "statuschange" and I was able to verify that when I move with the cursor from one field to another, the state of the field changes, but it does not jump in the function I do not understand why: this.contratoForm.statusChanges.suscribe(.... .
-
ararb78 over 6 years"statusChanges" evaluates the value "valid" or "invalid" and initially all inputs have the value invalid, so when I move from one to another with the cursor they are still invalids and do not enter the function.
-
ararb78 over 6 yearsThen, I think I need to check the touched status of the controls in my form.
-
Andriy over 6 yearsPlease check my UPDATE #2 in the answer and see STACKBLITZ (stackblitz.com/edit/angular-ab4tna?file=app%2Fapp.component.ts)