42

I have a simple form that needs to validate if the beginning and the end of the input is not space.

In HTML5, I will do this:

<input type="text" pattern="^(?!\s|.*\s$).*$">

What is the right property for validation pattern in the new Angular 2 ngControl directive? The official Beta API is still lacking documentation on this issue.

Matheus Lacerda
  • 5,983
  • 11
  • 29
  • 45
Downhillski
  • 2,555
  • 2
  • 27
  • 39
  • 5
    Currently there's no straightforward way to do it. You can write your own custom validator until this [pull request](https://github.com/angular/angular/pull/5561) lands, if it does at all. – Eric Martinez Jan 01 '16 at 19:55
  • 3
    Here is an example of how to do custom validation if you go down that path http://www.syntaxsuccess.com/viewarticle/forms-and-validation-in-angular-2.0 – TGH Jan 01 '16 at 20:13

6 Answers6

50

Now, you don't need to use FormBuilder and all this complicated valiation angular stuff. I put more details from this (Angular 2.0.8 - 3march2016): https://github.com/angular/angular/commit/38cb526

Example from repo :

<input [ngControl]="fullName" pattern="[a-zA-Z ]*">

I test it and it works :) - here is my code:

<form (ngSubmit)="onSubmit(room)" #roomForm='ngForm'  >
...
<input 
  id='room-capacity' 
  type="text" 
  class="form-control" 
  [(ngModel)]='room.capacity' 
  ngControl="capacity" 
  required
  pattern="[0-9]+" 
  #capacity='ngForm'>

Alternative approach (UPDATE June 2017)

Validation is ONLY on server side. If something is wrong then server return error code e.g HTTP 400 and following json object in response body (as example):

this.err = { 
    "capacity" : "too_small"
    "filed_name" : "error_name", 
    "field2_name" : "other_error_name",
    ... 
}

In html template I use separate tag (div/span/small etc.)

<input [(ngModel)]='room.capacity' ...>
<small *ngIf="err.capacity" ...>{{ translate(err.capacity) }}</small>

If in 'capacity' is error then tag with msg translation will be visible. This approach have following advantages:

  • it is very simple
  • avoid backend validation code duplication on frontend (for regexp validation this can either prevent or complicate ReDoS attacks)
  • control on way the error is shown (e.g. <small> tag)
  • backend return error_name which is easy to translate to proper language in frontend

Of course sometimes I make exception if validation is needed on frontend side (e.g. retypePassword field on registration is never send to server).

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
  • I just check (and test) changelog mention by Chris Snowden in his previous answer. He give the main hint. – Kamil Kiełczewski Mar 10 '16 at 21:29
  • What is the formula to covert patterns to this new type? e.g. : ng-pattern="/^(\+\91{1,2})\d{10}$/" – Vahid Alimohamadi Sep 15 '16 at 12:06
  • @VahidAlimohamadi I don't understand question, could you repeat it in other words ? – Kamil Kiełczewski Sep 15 '16 at 13:35
  • When i use regex string which works in angular 1.x as pattern, in Angular2, It won't work. Why? – Vahid Alimohamadi Sep 16 '16 at 11:32
  • 1
    @VahidAlimohamadi remove '/' at the begining and ad the end your regexp. so it should be in your case: pattern="^(\+\91{1,2})\d{10}$" (may be you must also remove or change backslashes '\' in your regexp) – Kamil Kiełczewski Sep 16 '16 at 20:41
  • @KamilKiełczewski, I'm still finding FormBuilder in Many Examples and Documents. can you help me with any document without FormBuilder please? – cracker Dec 13 '16 at 06:22
  • why without FormBuilder? You don't need to use form builder. You can add validation after type each character (you do it by input attributte (change)="validate($event)" ) and in validate function in Typescript check regexp and show hide some error message in you template – Kamil Kiełczewski Dec 13 '16 at 13:10
  • Using this method, how do you set the error message? – Levent Yumerov Jan 25 '17 at 13:57
  • 1
    @zennin You can try this (but I don't check it) : http://stackoverflow.com/questions/10361460/how-can-i-change-or-remove-html5-form-validation-default-error-messages – Kamil Kiełczewski Jan 25 '17 at 14:52
  • can you please help me to solve this https://stackoverflow.com/questions/52091334/password-validation-is-not-working-in-angular-5 @KamilKiełczewski – Zhu Aug 30 '18 at 08:36
11

Since version 2.0.0-beta.8 (2016-03-02), Angular now includes a Validators.pattern regex validator.

See the CHANGELOG

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
Chris Snowden
  • 4,982
  • 1
  • 25
  • 34
9

You could build your form using FormBuilder as it let you more flexible way to configure form.

export class MyComp {
  form: ControlGroup;

  constructor(@Inject()fb: FormBuilder) {  
    this.form = fb.group({  
      foo: ['', MyValidators.regex(/^(?!\s|.*\s$).*$/)]  
    });  
  }

Then in your template :

<input type="text" ngControl="foo" />
<div *ngIf="!form.foo.valid">Please correct foo entry !</div> 

You can also customize ng-invalid CSS class.

As there is actually no validators for regex, you have to write your own. It is a simple function that takes a control in input, and return null if valid or a StringMap if invalid.

export class MyValidators {
  static regex(pattern: string): Function {
    return (control: Control): {[key: string]: any} => {
      return control.value.match(pattern) ? null : {pattern: true};
    };
  }
}

Hope that it help you.

gentiane
  • 6,715
  • 3
  • 23
  • 34
5

custom validation step by step

Html template

  <form [ngFormModel]="demoForm">
  <input  
  name="NotAllowSpecialCharacters"    
  type="text"                      
  #demo="ngForm"
  [ngFormControl] ="demoForm.controls['spec']"
  >

 <div class='error' *ngIf="demo.control.touched">
   <div *ngIf="demo.control.hasError('required')"> field  is required.</div>
   <div *ngIf="demo.control.hasError('invalidChar')">Special Characters are not Allowed</div>
 </div>
  </form>

Component App.ts

import {Control, ControlGroup, FormBuilder, Validators, NgForm, NgClass} from 'angular2/common';
import {CustomValidator} from '../../yourServices/validatorService';

under class define

 demoForm: ControlGroup;
constructor( @Inject(FormBuilder) private Fb: FormBuilder ) {
    this.demoForm = Fb.group({
       spec: new Control('', Validators.compose([Validators.required,   CustomValidator.specialCharValidator])),
      })
}

under {../../yourServices/validatorService.ts}

export class CustomValidator {
    static specialCharValidator(control: Control): { [key: string]: any } {
   if (control.value) {
       if (!control.value.match(/[-!$%^&*()_+|~=`{}\[\]:";#@'<>?,.\/]/)) {            
           return null;
       }
       else {            
           return { 'invalidChar': true };
       }
   }

 }

 }
mani R
  • 361
  • 4
  • 16
1

My solution with Angular 4.0.1: Just showing the UI for required CVC input - where the CVC must be exactly 3 digits:

    <form #paymentCardForm="ngForm">         
...
        <md-input-container align="start">
            <input #cvc2="ngModel" mdInput type="text" id="cvc2" name="cvc2" minlength="3" maxlength="3" placeholder="CVC" [(ngModel)]="paymentCard.cvc2" [disabled]="isBusy" pattern="\d{3}" required />
            <md-hint *ngIf="cvc2.errors && (cvc2.touched || submitted)" class="validation-result">
                <span [hidden]="!cvc2.errors.required && cvc2.dirty">
                    CVC is required.
                </span>
                <span [hidden]="!cvc2.errors.minlength && !cvc2.errors.maxlength && !cvc2.errors.pattern">
                    CVC must be 3 numbers.
                </span>
            </md-hint>
        </md-input-container>
...
<button type="submit" md-raised-button color="primary" (click)="confirm($event, paymentCardForm.value)" [disabled]="isBusy || !paymentCardForm.valid">Confirm</button>
</form>
mkaj
  • 3,421
  • 1
  • 31
  • 23
0

Without make validation patterns, You can easily trim begin and end spaces using these modules.Try this.

https://www.npmjs.com/package/ngx-trim-directive https://www.npmjs.com/package/ng2-trim-directive

Thank you.

Dilshan
  • 35
  • 7