Jeb50
Jeb50

Reputation: 7037

How to Highlight and Display Default Validator Message?

This StackBlitz, I'd like to learn how to:

  1. highlight the input box and make *Required in red
  2. display a DEFAULT error message from validator when it fails minLength(4)

Upvotes: 0

Views: 889

Answers (2)

Eliseo
Eliseo

Reputation: 57939

Jeb, you has a type error when defined the FormGroup, see that if we has two or more validators you pass an array of validators

this.myForm = this.fb.group({
  uname: ['', [Validators.required, Validators.minLength(4)]] //<--is an array
});

About the class we can has in styles.css some like

input.ng-invalid.ng-touched {   //<--is necesary the "input", else a custom form
                                //control will be bordered too
  border: 1px solid red;
}

If we want only when "submited" we can use, e.g.

input.ng-invalid.ng-touched.submitted {
  border: 1px solid red;
}

And use a variable in our ts

submitted :boolean=false;

And our input add [class.submitted]

<input [class.submitted]="submitted" type="text" formControlName="uname" ..>  

About the repeater there're several aproach. One can be create a custom-error, one component like

@Component({
  selector: 'custom-error',
  template: `
    <small class="error" *ngIf="isInvalid" >
       <ng-content></ng-content>
    </small>
`,
styles:[`
.error{
  color:red
}
`]
})
export class ErrorComponent {
  @Input() submitted:boolean=true;
  get isInvalid() {
    const control = this.form.form.get(this.controlName);
    return this.submitted && control.touched && control.invalid && (this.error ? control.errors[this.error] : true);
  }
  constructor(@Optional() @Host() private form: FormGroupDirective,
    @Attribute("controlName") private controlName,
    @Attribute("error") private error) { }
}

Allow us write some like

//if we want not wait to submitted and a unique Validators
<custom-error controlName="uname" >Required</custom-error>

//if there're an unique Validators
<custom-error [submitted]="submitted" controlName="uname" >Required</custom-error>

//if we severals validators
<custom-error [submitted]="submitted" error="required" controlName="uname" >Required</custom-error>

We can imagine another kinds of "custom-errors" that only show one error

//this "defaultErrors should be in a external file and completed with other erros
//this allow us reemplace case we want "localize" our app

export const defaultErrors = {
  required: (error) => `This field is required`,
  minlength: ({ requiredLength, actualLength }) => `Expect ${requiredLength} but got ${actualLength}`,
  default:'field invalid' //<--add a string with the default error
}

@Component({
  selector: 'custom-error-unique',
  template: `
    <small class="error" *ngIf="hasError" >
       {{hasError}}
    </small>
`,
styles:[`
.error{
  color:red
}
`]
})
export class ErrorUniqueComponent {
   errors=defaultErrors
   @Input() submitted:boolean=true;
   @Input('errors') set _(value)
   {
       this.errors={...defaultErrors,...value}
   }

  @Input() submitted:boolean=true;
  @Input() errors:any=defaultErrors;

  get hasError() {
    const control = this.form.form.get(this.controlName);
    const invalid=this.submitted && control.touched && control.invalid
    let error=null
    if (invalid)
    {
       Object.keys(this.errors).forEach(x=>{
          if (control.errors[x] && !error)
          {
            error=this.errors[x](control.errors[x])
          }
       })
       if (!error)
            error=this.defaultErrors.default

    }
    return  error
  }
  constructor(@Optional() @Host() private form: FormGroupDirective,
    @Attribute("controlName") private controlName,
    @Attribute("error") private error) { }

}

In this stackblitz thre're the two custom-errors components

Even we can imagine that appears magically. Well, Netanel Basal think about it before us: see this great entry blog

Upvotes: 1

robert
robert

Reputation: 6152

You can add this style to styles.css

.has-error {
  border: 1px solid red;
}

then something like this to input:

<input type="text" formControlName="uname"  placeholder="Enter Name..." [ngClass]="{ 'has-error': myForm.controls?.uname.errors && (myForm.controls?.uname.dirty || myForm.controls?.uname.touched) }">

Demo

Upvotes: 1

Related Questions