How to validate white spaces/empty spaces? [Angular 2]
Asked Answered
Z

24

109

I would like to avoid white spaces/empty spaces in my angular 2 form? Is it possible? How can this be done?

Zoniazoning answered 30/8, 2016 at 20:58 Comment(2)
you just have to trim the field as two way data binding. You can consider a custom pipe tooSatang
Maybe this article can help you blog.angular-university.io/…Stacystadholder
M
18

Maybe this article can help you http://blog.angular-university.io/introduction-to-angular-2-forms-template-driven-vs-model-driven/

In this approach, you have to use FormControl then watch for value changes and then apply your mask to the value. An example should be:

...
form: FormGroup;
...


ngOnInit(){
    this.form.valueChanges
            .map((value) => {
                // Here you can manipulate your value
                value.firstName = value.firstName.trim();
                return value;
            })
            .filter((value) => this.form.valid)
            .subscribe((value) => {
               console.log("Model Driven Form valid value: vm = ",JSON.stringify(value));
            });

}
Magnificence answered 2/9, 2016 at 19:25 Comment(0)
F
253

You can create a custom validator to handle this.

new FormControl(field.fieldValue || '', [Validators.required, this.noWhitespaceValidator])

Add noWhitespaceValidator method to your component

public noWhitespaceValidator(control: FormControl) {
    return (control.value || '').trim().length? null : { 'whitespace': true };       
}

and in the HTML

<div *ngIf="yourForm.hasError('whitespace')">Please enter valid data</div>
Fayfayal answered 24/3, 2017 at 12:41 Comment(8)
I think I prefer this approach because its makes the rule reusable. Even being mine response marked as the correct one.Stacystadholder
To make it reusable in other components: replace 'public' with 'export function', then put it into a file (eg: src/app/utils/no-whitespace.validator.rs), and add the line to import FormControl. Now you can import this validator into any control you like :)Faina
@Faina you are absolutely right.. that is how we need to write and maintain the code.Fayfayal
How could the noWhitespaceValidator be modified to allow for strictNullChecks: true to be set in tsconfig.json?Oscular
this indeed is a better, clean , reusable and explicit approach. Should have been the accepted answer @ZoniazoningKimes
How can I make this for password fieldScroop
//above answer is perfect only suggesting one check to avoid collision with angular required validator. public noWhitespaceValidator(control: FormControl) { const isWhitespace = control.value.length > 0 && (control.value).trim().length === 0; const isValid = !isWhitespace; return isValid ? null : { 'whitespace': true }; }Defecate
I found this more convenient and easy to customize.Uigur
W
34

I think a simple and clean solution is to use pattern validation.

The following pattern will allow a string that starts with white spaces and will not allow a string containing only white spaces:

/^(\s+\S+\s*)*(?!\s).*$/

It can be set when adding the validators for the corresponding control of the form group:

const form = this.formBuilder.group({
            name: ['', [
                Validators.required,
                Validators.pattern(/^(\s+\S+\s*)*(?!\s).*$/)
            ]]
        });
Warrington answered 2/11, 2020 at 15:4 Comment(3)
Validators.pattern(/[\S]/) is cleaner and more readable but will also require at least one character.Outland
@MarioFigueiredo your answer is correct, but you forgot g to catch all white space. so it would be Validators.pattern(/[\S]/gExpect
You forgot to add ). Should be: Validators.pattern(/[\S]/g)Yecies
M
18

Maybe this article can help you http://blog.angular-university.io/introduction-to-angular-2-forms-template-driven-vs-model-driven/

In this approach, you have to use FormControl then watch for value changes and then apply your mask to the value. An example should be:

...
form: FormGroup;
...


ngOnInit(){
    this.form.valueChanges
            .map((value) => {
                // Here you can manipulate your value
                value.firstName = value.firstName.trim();
                return value;
            })
            .filter((value) => this.form.valid)
            .subscribe((value) => {
               console.log("Model Driven Form valid value: vm = ",JSON.stringify(value));
            });

}
Magnificence answered 2/9, 2016 at 19:25 Comment(0)
D
15

Prevent user to enter space in textbox in Angular 6

<input type="text" (keydown.space)="$event.preventDefault();" required />
Disequilibrium answered 18/12, 2018 at 11:4 Comment(5)
You can still paste spaces, or use Alt+0160.Muckworm
Just for anyone else who notices pasting still works, you can use a custom directive to disable pasting. See #47385452Lukash
@Lukash you can, but what if a user wants to paste something (legal)? Disabling pasting is making usability worse.Demote
@DanielShatz you can just call change event inline function for that. like (change)="yourvalue = yourvalue.trim()" in input element.Rillings
The question was to prevent whitespace/empty spaces. This prevents any space. What if I want a space between two words?Pisistratus
M
12
    export function noWhitespaceValidator(control: FormControl) {
       const isSpace = (control.value || '').match(/\s/g);
       return isSpace ? {'whitespace': true} : null;
}

to use

 password: ['', [Validators.required, noWhitespaceValidator]]

In template/html

<span *ngIf="newWpForm.get('password').hasError('whitespace')">
    password cannot contain whitespace
</span>
Myles answered 19/5, 2020 at 8:22 Comment(2)
Best and standard approach to validate whitespace .. good thing is we can use this validator across form groupsSurfactant
For those users copy/pasting this answer into their projects: please allow whitespace in your passwords. There is nothing wrong with a space in a password.Supercolumnar
P
10

If you are using Angular Reactive Forms you can create a file with a function - a validator. This will not allow only spaces to be entered.

import { AbstractControl } from '@angular/forms';
export function removeSpaces(control: AbstractControl) {
  if (control && control.value && !control.value.replace(/\s/g, '').length) {
    control.setValue('');
  }
  return null;
}

and then in your component typescript file use the validator like this for example.

this.formGroup = this.fb.group({
  name: [null, [Validators.required, removeSpaces]]
});
Prefect answered 4/11, 2018 at 17:35 Comment(2)
I know this answer is over a year old, but I just tried it. When I created my form control, i defaulted it to '' instead of null and this caused an infinite loop some how. I changed my default to null and continued testing. If I went into the field, typed a few characters and then deleted them, it said the field was valid even though it should have fail required validation. It's a shame. I really liked this solution.Acrid
I was trying this approach in my code, but it was not throwing required error even control had empty value as ''. so returned in the function {required : true} below control.setvalue(''); and it worked like a charm. Thanks.Eklund
S
10

An alternative would be using the Angular pattern validator and matching on any non-whitespace character.

const nonWhitespaceRegExp: RegExp = new RegExp("\\S");

this.formGroup = this.fb.group({
  name: [null, [Validators.required, Validators.pattern(nonWhiteSpaceRegExp)]]
});
Statics answered 31/10, 2019 at 13:8 Comment(0)
H
6

What I did was created a validator that did the samething as angular for minLength except I added the trim()

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


@Injectable()
export class ValidatorHelper {
    ///This is the guts of Angulars minLength, added a trim for the validation
    static minLength(minLength: number): ValidatorFn {
        return (control: AbstractControl): { [key: string]: any } => {
            if (ValidatorHelper.isPresent(Validators.required(control))) {
                return null;
            }
             const v: string = control.value ? control.value : '';
            return v.trim().length < minLength ?
                { 'minlength': { 'requiredLength': minLength, 'actualLength': v.trim().length } } :
                null;
        };
    }

    static isPresent(obj: any): boolean {
        return obj !== undefined && obj !== null;
    }
}

I then in my app.component.ts overrode the minLength function provided by angular.

import { Component, OnInit } from '@angular/core';    
import { ValidatorHelper } from 'app/common/components/validators/validator-helper';
import { Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {  
  constructor() { }

  ngOnInit(): void {       
    Validators.minLength = ValidatorHelper.minLength;
  }
}

Now everywhere angular's minLength built in validator is used, it will use the minLength that you have created in the helper.

Validators.compose([
      Validators.minLength(2)         
    ]);
Hujsak answered 28/9, 2017 at 21:10 Comment(0)
R
5

Following directive could be used with Reactive-Forms to trim all form fields so standart Validators.required work fine:

@Directive({
  selector: '[formControl], [formControlName]',
})
export class TrimFormFieldsDirective {
  @Input() type: string;

  constructor(@Optional() private formControlDir: FormControlDirective, 
              @Optional() private formControlName: FormControlName) {}

  @HostListener('blur')
  @HostListener('keydown.enter')
  trimValue() {
    const control = this.formControlDir?.control || this.formControlName?.control;
    if (typeof control.value === 'string' && this.type !== 'password') {
      control.setValue(control.value.trim());
    }
  }
}
Rob answered 19/6, 2020 at 6:36 Comment(4)
This solution can be used for entire application, if you are using reactive forms. Best solution.Tore
github.com/anein/angular2-trim-directive is a simple solution which works out of the boxJump
Solution works fine with Angular v13.3. Just a note that following import statements will be needed: import { Directive, HostListener, Input, Optional } from '@angular/core'; import { FormControlDirective, FormControlName } from '@angular/forms';Santo
Works great on Angular v14... However, on a username field, control.setValue does not fully update the control resulting in the Chrome autofill save password prompt still including the spaces. Using control.patchValue instead corrects the issue. And for all of you newbies out there, don't forget to import this directive into your global app or shared module.Aspa
P
4

This is a slightly different answer to one below that worked for me:

public static validate(control: FormControl): { whitespace: boolean } {
    const valueNoWhiteSpace = control.value.trim();
    const isValid = valueNoWhiteSpace === control.value;
    return isValid ? null : { whitespace: true };
}
Peekaboo answered 27/2, 2019 at 4:50 Comment(0)
M
3

To avoid the form submition, just use required attr in the input fields.

<input type="text" required>

Or, after submit

When the form is submited, you can use str.trim() to remove white spaces form start and end of an string. I did a submit function to show you:

submitFunction(formData){

    if(!formData.foo){
        // launch an alert to say the user the field cannot be empty
        return false;
    }
    else
    {
        formData.foo = formData.foo.trim(); // removes white 
        // do your logic here
        return true;
    }

}
Magnificence answered 30/8, 2016 at 21:14 Comment(3)
Thank you for your help, but what I need is to avoid the user to just add white spaces and save the form. I believe is possible to validate it in some way. What do you think?Zoniazoning
I have not used input mask with angular 2 form yet. If i do, I'll help you. But now I can't. Try to search for masked input for angular 2 ;)Stacystadholder
Thank you! I'll try to find it.Zoniazoning
G
3

To automatically remove all spaces from input field you need to create custom validator.

removeSpaces(c: FormControl) {
  if (c && c.value) {
    let removedSpaces = c.value.split(' ').join('');
    c.value !== removedSpaces && c.setValue(removedSpaces);
  }
  return null;
}

It works with entered and pasted text.

Garrick answered 10/7, 2019 at 11:11 Comment(3)
I found this solution to be the most portable and less invasive. Using the reactive forms own validation system. It works in every case and can be used around all the the app. Good Job! +1Ningpo
Why not just use .trim() instead of .spilit(' ').join('')?Tunny
@Tunny .trim removes whitespace at the beginning and end of the string whereas split/join removes all spaces (and only spaces, not all whitespace eg, tab, newline) anywhere in the string.Dentilabial
T
3

I had a requirement where in the Firstname and Lastname are user inputs which were required fields and user should not be able to hit space as the first character.

Import AbstractControl from node_modules.

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

check if the first character is space If yes then blank the value and return required: true. If no return null

export function spaceValidator(control: AbstractControl) {
if (control && control.value && !control.value.replace(/\s/g, '').length) {
    control.setValue('');
    console.log(control.value);
    return { required: true }
}
else {
    return null;
}
}

the above code will trigger an error if the first character is space and will not allow space to be the first character.

And in form builder group declare

this.paInfoForm = this.formBuilder.group({
        paFirstName: ['', [Validators.required, spaceValidator]],
        paLastName: ['', [Validators.required, spaceValidator]]
})
Transmute answered 14/1, 2020 at 18:3 Comment(0)
R
3

To validate white space in starting in an input you can just call change event and do inline function for that.

<input type="text" class="form-control"                     
            placeholder="First Name without white space in starting"
            name="firstName"
            #firstName="ngModel"
            [(ngModel)]="user.FirstName"
            (change) ="user.FirstName = user.FirstName.trim()"
            required/>
Rillings answered 5/10, 2020 at 12:51 Comment(0)
C
3

If you are using reactive forms in Angular 2+, you can remove leading and trailing spaces with the help of (blur)

app.html

<input(blur)="trimLeadingAndTrailingSpaces(myForm.controls['firstName'])" formControlName="firstName" />

app.ts

public trimLeadingAndTrailingSpaces(formControl: AbstractControl) {
    if (formControl && formControl.value && typeof formControl.value === 'string') {
        formControl.setValue(formControl.value.trim());
    }
}
Critta answered 30/1, 2021 at 14:24 Comment(0)
J
2

In your app.component.html

<form [formGroup]="signupForm">

           <input  type="text" name="name" [formControl]="signupForm.controls['name']"
              placeholder="First Name"
              required
            />
     <small
            *ngIf="signupForm.controls['name'].hasError('pattern')"
            class="form-error-msg"
            >First Name without space</small>

    </form>

In your app.componen.ts file

import { Validators, FormGroup, FormControl } from "@angular/forms";
signupForm: FormGroup;
ngOnInit(){
this.signupForm = new FormGroup({
  name: new FormControl("", [
    Validators.required,
    Validators.pattern("^[a-zA-Z]+$"),
    Validators.minLength(3)
  ])
})
Joniejonina answered 4/3, 2020 at 6:2 Comment(0)
C
1

I am late to the party, but I found most answers not fully functional for my use case. I am using regular expression matching, which detects UTF 8 Whitespace correctly (.trim() does not). Additionally I added a null value check. Code is typescript but should be easy to convert to javascript.

notOnlyWhitespaceValidator(control: AbstractControl) {
    const isWhitespace = control.value && control.value.length > 0 && (control.value as string).match(/[^-\s]/) === null;
    const isValid = !isWhitespace;
    return isValid ? null : { 'only-whitespace': true };
  }

Here is a test suite (jest)

  describe('notOnlyWhitespaceValidator', () => {
    it('should not trigger on missing value', () => {
      expect(CustomValidators.notOnlyWhitespaceValidator(new FormControl(''))).toEqual(null);
      expect(CustomValidators.notOnlyWhitespaceValidator(new FormControl())).toEqual(null);
    });

    it('should trigger on only whitespace', () => {
      expect(CustomValidators.notOnlyWhitespaceValidator(new FormControl(' '))).toEqual({ 'only-whitespace': true });
      expect(CustomValidators.notOnlyWhitespaceValidator(new FormControl('\n'))).toEqual({ 'only-whitespace': true });
      // check utf 8 zero with space
      const utf8Space = '\ufeff';
      expect(CustomValidators.notOnlyWhitespaceValidator(new FormControl(utf8Space))).toEqual({
        'only-whitespace': true,
      });
    });

    it('should not trigger on valid input', () => {
      expect(CustomValidators.notOnlyWhitespaceValidator(new FormControl(' Whatever is valid '))).toEqual(null);
      expect(CustomValidators.notOnlyWhitespaceValidator(new FormControl('!'))).toEqual(null);
    });
  });
Casebook answered 11/8, 2022 at 5:10 Comment(0)
R
0

After lots of trial i found [a-zA-Z\\s]* for Alphanumeric with white space

Example:

New York

New Delhi

Rici answered 26/7, 2019 at 11:0 Comment(0)
P
0

i have used form valueChanges function to prevent white spaces. every time it will trim all the fields after that required validation will work for blank string.

Like here:-

this.anyForm.valueChanges.subscribe(data => {
   for (var key in data) {
        if (data[key].trim() == "") {
          this.f[key].setValue("", { emitEvent: false });
        }
      }
    }

Edited --

if you work with any number/integer in you form control in that case trim function will not work directly use like :

this.anyForm.valueChanges.subscribe(data => {
  for (var key in data) {
        if (data[key] && data[key].toString().trim() == "") {
          this.f[key].setValue("", { emitEvent: false });
        }
      }  
  }
Pastorale answered 5/8, 2019 at 9:48 Comment(1)
You can still paste spaces or use Alt+0160Vyse
P
0

In hello.component.html

<input [formControl]="name" />
<div *ngIf="name.hasError('trimError')" > {{ name.errors.trimError.value }} </div>

In hello.component.ts

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

const trimValidator: ValidatorFn = (text: FormControl) => {
  if (text.value.startsWith(' ')) {
    return {
      'trimError': { value: 'text has leading whitespace' }
    };
  }
  if (text.value.endsWith(' ')) {
    return {
      'trimError': { value: 'text has trailing whitespace' }
    };
  }
  return null;
};`

export class AppComponent {
  control = new FormControl('', trimValidator);
}

Example Code

Psittacine answered 26/2, 2020 at 6:36 Comment(0)
E
0
export function NoWhitespaceValidator(): ValidatorFn {
    return (control: AbstractControl): any => {
        window.setTimeout(() => {
            if (control.value && control.value != '') {
                let trimedvalue = control.value.replace(/\s/g, '');
                control.setValue(trimedvalue);
            }
        }, 10);
    };
}


username: ['', Validators.compose([Validators.required, NoWhitespaceValidator()])],
Expendable answered 20/10, 2021 at 10:6 Comment(1)
Why the set timeout? To give users a chance to undo?Rebus
A
0

you can simply add a pattern validator

Validators.pattern('[\\S]{1,}[\\S\\s]*|[\\s]*[\\S]{1,}[\\S\\s]*')

this will provide a check for white space in leading or later section.

Arsyvarsy answered 24/8, 2022 at 7:13 Comment(0)
E
0

It is better to create custom validator using Angular code and customise it like this:

export function required(control: AbstractControl): ValidationErrors | null {
  return isEmptyInputValue(control?.value) ? {'required': true} : null;
}

function isEmptyInputValue(value: any): boolean {
  return value == null ||
    (typeof value === 'string' && value.trim().length === 0) ||
    (Array.isArray(value) && value.length === 0);
}

then you can use your own required validator instead of angular one.

Edna answered 1/11, 2022 at 14:17 Comment(0)
S
0

the following only passes if the string has 0 spaces...

Validators.pattern( /^[\S]*$/ )

https://regexr.com/7n6o1

Specify answered 14/11, 2023 at 12:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.