-1

From here: https://stackoverflow.com/a/42999816/462608

This is what I have tried:

whitespace-validator.directive.ts

import { Directive } from '@angular/core';
import { AbstractControl, FormControl, ValidationErrors } from '@angular/forms';

@Directive({
  selector: '[appWhitespaceValidator]'
})

export class WhitespaceValidatorDirective 
{
  constructor() {}

  static appWhitespaceValidator( control: FormControl ): ValidationErrors 
  {
    const isWhitespace = (control.value || '').trim().length === 0;
    const isValid      = !isWhitespace;

    return isValid ? null : { 'whitespace': true };
  }
}

In xyz.ts

import { WhitespaceValidatorDirective } from '../whitespace-validator.directive'

...

 this.objFormGroup = this.objFormBuilder.group(
      {
        blogTitle: [ this.blogs[this.mBlogId].title, [Validators.required, Validators.minLength(5)  ] ],
        body:      [ this.blogs[this.mBlogId].body ],
        category:  [ this.blogs[this.mBlogId].category ]
      } )

  get getBlogTitle()
  {
    return this.objFormGroup.get('blogTitle') as FormControl;
  }

In xyz.html

<div *ngIf = "getBlogTitle.errors?.appWhitespaceValidator">
  No spaces are allowed.
</div>

Please show what is the correct way of using this validator directive. There are no errors here but the form is still not complaining w.r.t whitespaces.

What is the way to use the custom validator in HTML with "reactive" form?

Aquarius_Girl
  • 21,790
  • 65
  • 230
  • 411

2 Answers2

3

Your Whitespace validator is incorrect, try this -

import { AbstractControl, ValidatorFn } from '@angular/forms';

@Directive({
    selector: '[appWhitespaceValidator]',
    providers: [{ provide: NG_VALIDATORS, useExisting: NoWhitespaceDirective, multi: true}]
})
export class NoWhitespaceDirective implements Validator {

    validate(control: AbstractControl): { [key: string]: any } {
        const isWhitespace = (control.value || '').trim().length === 0;
        const isValid      = !isWhitespace;
        return isValid ? null : { 'whitespace': true };
    }
}
Zaxoosh
  • 167
  • 12
1

Your whitespace validator directive should be :-

import { AbstractControl, ValidatorFn } from '@angular/forms';

@Directive({
    selector: '[appWhitespaceValidator]',
    providers: [{ provide: NG_VALIDATORS, useExisting: WhitespaceValidatorDirective , multi: true}]
})
export class WhitespaceValidatorDirective implements Validator {

    validate(control: AbstractControl): { [key: string]: any } {
        const isValid      = !control.value || (!control.value.startsWith(' ') && !control.value.endsWith(' '));
        return isValid ? null : { 'whitespace': true };
    }
}

USE it like :-

<input type="text" id="name" name="getBlogTitle" [(ngModel)]="hero.name" #name="ngModel" appWhitespaceValidator>

For Errors :-

<div *ngIf = "getBlogTitle.errors?.whitespace">
  No spaces are allowed.
</div>

Documentation Links

useExisting, multi and other dependency injection providers :- https://angular.io/guide/dependency-injection-providers

How to add custom validators without directive :-

https://codecraft.tv/courses/angular/advanced-topics/basic-custom-validators/

(NG_VALIDATORS) will be part of this link.

Explanations:

This class is a directive because of @directive decorator can be used as an attribute on any form element for validating the input, can be as an attribute like we used above on input tag. These kind of directives are known as attribute directives in angular. the only thing is this directive is implementing validator class.

Whenever you want add custom validators in form you have to provide NG_VALIDATORS, useExisting tells us to use our class as an validator, multi is to tell that there can be other validators too i.e. can be multiple custom validators. so providers array can have like providers : [{ provide: NG_VALIDATORS, useExisting: NoWhitespaceDirective, multi: true}, { provide: NG_VALIDATORS, useExisting: NoSpecialCharacterDirective, multi: true}]

there is a way to make it work without directive, you can add custom validators directly. depends case to case. If you want to create a validator, that should be available throughout your application on various forms, you go for directive. if its for specific form, you can create a custom validator in that component and can attach it.

Problem With your validation code:-

you were checking that (control.value || '') as soon as you type anything, you will get the value right not blank string. so lets say you input 'abc', then you call trim, which will convert it into 'abc'.length === 0. which will say false, because its 3. then you were setting is valid to ! of above result. so isValid will become true and your validation will fail.

developer033
  • 24,267
  • 8
  • 82
  • 108
Aakash Garg
  • 10,649
  • 2
  • 7
  • 25
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/215290/discussion-on-answer-by-aakash-garg-validator-directive-for-reactive-forms-in-an). – Samuel Liew Jun 04 '20 at 09:15