21

I'm having trouble getting the Angular 5 Validators.pattern to work. I've tried every regex that SHOULD normally work, but it's not working. I read that Validators.pattern requires a different format, but I can't seem to find it...

Any ideas what the Validators.pattern should be to

(1) allow only numbers, positive and negative

and

(2) allow only numbers, positive and negative, optionally with up to 2 decimal places

Valid examples would be: 1 1.2 1.22 -21 -21.48

Anything with any letter in it would be invalid.

Thanks for your help!

Matt
  • 3,206
  • 4
  • 24
  • 26
  • 1
    Can you add the regexes you tried? Is `.1` valid? What about `-0`, `0.00`, `01`? – ctwheels Feb 26 '18 at 19:51
  • Thanks @ctwheels ! Yes, .1 would be valid. -0, 0.00 or 01 ideally would not be, but it's not a big issue if they are. I tried every regex from this post: https://stackoverflow.com/questions/2811031/decimal-or-numeric-values-in-regular-expression-validation – Matt Feb 26 '18 at 19:54
  • Just a background on WHY I'm doing this... This is for validation in Safari. In Chrome I have have a reactive form input and make it type="number" and it will block the user from entering letters etc. In Safari that doesn't work, you can enter "abc" in a number input. So I need this validation there to prevent that :) – Matt Feb 26 '18 at 19:56
  • Try `-?[0-9]+(\.[0-9][0-9]?)?` or `-?\d+(\.\d{1,2})?` both of these assume that you must have both at least one digit before and one after the decimal place. – penleychan Feb 26 '18 at 20:00
  • Can you show your actual code for that you're having problems with? For example Validator.pattern(["^[1-9]\d*$"]); – Narm Feb 26 '18 at 20:32
  • The one that seems to be working best it -?[0-9]+(\.[0-9][0-9]?)? , it does the number validation (with/without decimal) but it's still allowing me to enter letters in Safari. So the whole code for that is Validators.pattern('-?[0-9]+(\.[0-9][0-9]?)?') Is this maybe a Safari-specific thing, that it's ignoring the Validators.pattern ? – Matt Feb 26 '18 at 20:42

6 Answers6

39

After trying so many regex expressions, none was working in Safari. So here's what I did...

First, I used the regex when creating the form control:

new FormControl({value: field.value}, [Validators.required, Validators.pattern(/^-?(0|[1-9]\d*)?$/)])

Then, in the input itself I added an (input) event:

<input matInput (input)="validateInput(field)" [placeholder]="field.label" type="number" [formControlName]="field.id" [id]="field.id">

And that function looks like this:

validateInput(field) {

    this.detailForm.patchValue({ [field.id]: this.detailForm.controls[field.id].value }); }

}

If you enter an invalid character (e.g. a-z) in Safari, it doesn't store it in the field control's value. It only stores valid values (numbers) there. So I'm just patching the value with the stored value -- if it's valid, with numbers, it's fine; if it's invalid, with other characters, then it will replace the input with an empty string.

Works perfectly on all browsers. Hope this helps someone :)

Matt
  • 3,206
  • 4
  • 24
  • 26
  • Is there any way without using "Validators.required"? Because I have a similar situation and in my case input field can be empty – Süleyman K Aug 02 '18 at 13:21
  • @SüleymanK just leave out the Validators.required, and only have Validators.pattern. That should work, no? So it would look like this: new FormControl({value: field.value}, [Validators.pattern(/^-?(0|[1-9]\d*)?$/)]) – Matt Aug 02 '18 at 17:06
  • 1
    I couldn't make it work. It doesn't call pattern when there is no Validators.required. Do I do something wrong? :) – Süleyman K Aug 07 '18 at 06:48
  • I think it must be something else in your code, because leaving out the Validators.required won't cause a problem. You can just have the Validators.pattern without Validators.required, it should still work. You can remove the [ ] around the validators, that's the only thing I see here. So: new FormControl({value: field.value}, Validators.pattern(/^-?(0|[1-9]\d*)?$/)) Not sure that will make any difference though. If it's still not working there must be something else. Try posting a new question here with your full code. – Matt Aug 07 '18 at 13:14
  • I tried to use type:text in input instead of number and it works in that way :) no need for Validators.required when you use text. But like I said when I use number, it does'nt work. Ok I will try some more solutions and not work, I will ask in here :) – Süleyman K Aug 08 '18 at 15:48
  • @SüleymanK Did you ever found a solution for this. I'm using number and indeed pattern does not work without required validator. Super strange. As soon as I put required it begins working flawlessly. – Merv Apr 10 '19 at 16:09
  • @Merv it's working fine for me with or without the required validator. Here's the code without: new FormControl( {value: field.value || ''}, Validators.pattern(/^-?(0|[1-9]\d*)?$/) – Matt Apr 15 '19 at 16:55
  • 1
    @Matt It didn't work for me. Because input type number doesn't allow pattern. If you have input type text it works. I had to make a custom validator and implement the regex there. This was only for friendly usability since using a input type text when only numbers are allowed, gives you the whole keyboard instead of the keyboard with only numbers on mobile. One great thing to note is that if your input type is number and you put a non-numeric character the value will always be null or undefined. But you wont be able to have custom validations because default pattern validator does not work. – Merv Apr 15 '19 at 22:22
12

Allow only integer numbers without symbols.

Validators.pattern(/^[0-9]\d*$/)

Numbers start from one

Validators.min(1)
Andriy Danylko
  • 129
  • 1
  • 4
6

Don't forget to use with quotes and double backslash in order to make your regex work like it's supposed Validators.pattern('\\-?\\d*\\.?\\d{1,2}') or you can make variable for that

const regexPattern = /\-?\d*\.?\d{1,2}/;
Validators.pattern(regexPattern);
Yevheniy Potupa
  • 537
  • 5
  • 12
6

This one work for me in Aungular 7

const numericNumberReg= '^-?[0-9]\\d*(\\.\\d{1,2})?$';

this.$form = this.$builder.group({
      cost: ['', [Validators.required,Validators.pattern(numericNumberReg)]],
    });
SwissCodeMen
  • 4,222
  • 8
  • 24
  • 34
San Jaisy
  • 15,327
  • 34
  • 171
  • 290
2

You can try with this regex '^-?[0-9]\d*(\.\d{1,2})?$'. And your form builder will be like below:

this.yourForm= this.formBuilder.group({
    amount: [this.amount, [Validators.required, Validators.pattern('^-?[0-9]\\d*(\\.\\d{1,2})?$')]]
});
 
SwissCodeMen
  • 4,222
  • 8
  • 24
  • 34
Abdus Salam Azad
  • 5,087
  • 46
  • 35
0

I used the valueChanges property on my fromControl to filter out any non-numeric characters and update its own value, which seems to be a reliable (if over-engineered) solution and avoids having a separate input on the field. But full credit to @Matt for the principle.

This is compatible with the inbuilt Validators.min and Validators.max, but the field in your HTML must have type="text"rather than type="number", otherwise you get some odd behaviour.

myNumberField = new FormControl<number | null>(null);

myNumberFieldSub = this.myNumberField.valueChanges.subscribe(value => {
  let filteredValue = null;
  if (!!value) {
    filteredValue = parseInt(value.toString().replace(/[^0-9]*/, ''));
    if (isNaN(filteredValue)) {
      // Set field back to null if filtered value is not a number
      filteredValue = null;
    }
  }
  this.myNumberField.setValue(filteredValue, { emitEvent: false });
});

Don't forget to unsubscribe!!

Matt Saunders
  • 3,538
  • 2
  • 22
  • 30