3

I would like to simplify the code below:

<div *ngIf="form1.errors?.checkDate && (form1.touched || form1.dirty)" class="cross-validation-error-message alert alert-danger">
    Date can't be in the future.
</div>
<div *ngIf="form1.errors?.notAfterDate && (form1.touched || form1.dirty)" class="cross-validation-error-message alert alert-danger">
    Birth Date must be after 1/1/1800.
</div>

It should have only 1 div *ngif and pass the error message as a value instead of hardcoding or use a ngFor?

Any help on this is much appreciated. Thanks.

Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
Harry
  • 546
  • 6
  • 22
  • 50
  • Make a map with errors and corresponding texts. And then just pass this map and an error path to the function – Sergey Aug 31 '19 at 20:22
  • you can either make `errors` be an array or iterate over `Object.keys(errors)` and in both cases use `ngFor` – dee zg Aug 31 '19 at 20:24
  • Thanks both for your immediate comments & possible solution. Is there a simple example available or possible? – Harry Aug 31 '19 at 20:28
  • Shameless plug: Use https://ngx-valdemort.ninja-squad.com. That's exactly why I wrote this library. – JB Nizet Sep 01 '19 at 09:18

2 Answers2

3

A common technique to manage multiple Angular Form validation messages is to store them in a map.

public validationMessages = {
  'firstName': [
    { type: 'required', message: 'First Name is required' },
    { type: 'maxlength', message: 'First Name may only contain 5 characters.' }
  ],
  'lastName': [
    { type: 'required', message: 'Last Name is required' },
    { type: 'pattern', message: 'Last Name may not be "Smith".' }
  ],
  'email': [
    { type: 'required', message: 'Email is required' },
    { type: 'email', message: 'Enter a valid email' }
  ]
}

HTML Template

In the template, use NgFor to iterate through the validation messages for the desired form control.

<label>
  Email:
  <input type="email" autocomplete="email" formControlName="email" required>
</label>
<!-- Validation Errors -->
<div *ngFor="let validation of validationMessages.email">
  <div *ngIf="profileForm.get('email').hasError(validation.type) && (profileForm.get('email').dirty || profileForm.get('email').touched)">
    <small style="color:red;">{{validation.message}}</small>
  </div>
</div>

Example

See Stackblitz Demo

Community
  • 1
  • 1
Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
0

I like has an error-component.

@Component({
  selector: 'app-error',
  template: `
  <small class="form-text text-danger" *ngIf="(control.touched || control.dirty)
         && control.invalid && (error?control.errors[error]:true)" >
       <ng-content></ng-content>
    </small>`
})
export class ErrorComponent {

  @Input('controlName') controlName: string;
  @Input('error') error: string

  @Input('control') control:any

  visible: boolean = false;

  constructor(@Optional() @Host() public form: FormGroupDirective) { }

  ngOnInit() {
    if (this.form) {
      this.control = this.form.form.get(this.controlName) as FormControl
    }
  }
}

You can use in a formGroup, use controlName input to indicate the control, and error input if you has severals Validators and want discriminate

<form [formGroup]="form">
  <input formControlName="email">
    <app-error controlName="email" error="required">Email required.</app-error>
    <app-error controlName="email" error="email">incorrect email </app-error>
</form>

form=new FormGroup({
    email:new FormControl('',[Validators.required,Validators.email])
  })

Or standalone, use [control] input to indicate the control

<input [formControl]="control">
<app-error [control]="control">control required</app-error>

control=new FormControl('',Validators.required)

See the stackblitz demo

Eliseo
  • 50,109
  • 4
  • 29
  • 67