Search code examples
validationangularformbuilder

Validation Error Message not getting displayed for custom validation in Angular 2


I have a register form where user need to provide username. When customer enters username, I want to show validation error message if that username already exists in db or not.

register.html

 <-- code here-->
<div class="form-group">
            <label for="username" class="col-sm-3 control-label">UserName</label>
            <div class=" col-sm-6">
             <input type="text" ngControl="userName" maxlength="45" class="form-control" [(ngModel)]="parent.userName" placeholder="UserName" #userName="ngForm" required data-is-unique/>
                <validation-message control="userName"></validation-message>
            </div>
        </div>
 <--code here-->

register.component.ts

import {Component} from 'angular2/core';
import {NgForm, FormBuilder, Validators, FORM_DIRECTIVES} from  'angular2/common';
   import {ValidationService} from '../services/validation.service';
  import {ValidationMessages} from './validation-messages.component';
  @Component({
    selector: 'register',
    templateUrl: './views/register.html',
    directives: [ROUTER_DIRECTIVES, ValidationMessages, FORM_DIRECTIVES],
    providers: []
   })
  export class ParentSignUpComponent {
   parentSignUpForm: any;
   constructor(private _formBuilder: FormBuilder) {
    this._stateService.isAuthenticatedEvent.subscribe(value => {
        this.onAuthenticationEvent(value);
    });
    this.parent = new ParentSignUpModel();
    this.parentSignUpForm = this._formBuilder.group({
        'firstName': ['', Validators.compose([Validators.required, Validators.maxLength(45), ValidationService.nameValidator])],
        'middleName': ['', Validators.compose([Validators.maxLength(45), ValidationService.nameValidator])],
        'lastName': ['', Validators.compose([Validators.required, Validators.maxLength(45), ValidationService.nameValidator])],
        'userName': ['', Validators.compose([Validators.required, ValidationService.checkUserName])]
    });
}
}

validation-message.component

import {Component, Host} from 'angular2/core';
import {NgFormModel} from 'angular2/common';
import {ValidationService} from '../services/validation.service';

@Component({
   selector: 'validation-message',
   inputs: ['validationName: control'],
   template: `<div *ngIf="errorMessage !== null" class="error-message"> {{errorMessage}}</div>`
    })
     export class ValidationMessages {
    private validationName: string;
    constructor (@Host() private _formDir: NgFormModel) {}
    get errorMessage() {
    let control = this._formDir.form.find(this.validationName);
    for (let propertyName in control.errors) {
        if (control.errors.hasOwnProperty(propertyName) && control.touched)   {
            return ValidationService.getValidatorErrorMessage(propertyName);
        }
      }
    return null;
  }
 }

validation-service.ts

  import {Injectable, Injector} from 'angular2/core';
  import {Control} from 'angular2/common';
  import {Observable} from 'rxjs/Observable';
  import {Http, Response, HTTP_PROVIDERS} from 'angular2/http';
  import 'rxjs/Rx';       
  interface ValidationResult {
    [key:string]:boolean;
    }
 @Injectable()
 export class ValidationService {
   static getValidatorErrorMessage(code: string) {
    let config = {
      'required': 'This field is required!',
      'maxLength': 'Field is too long!',
      'invalidName': 'This field can contain only alphabets, space, dot, hyphen, and apostrophe.',
      'userAlreadyInUse': 'UserName selected already in use! Please try another.'
};
return config[code];
}
static checkUserName(control: Control): Promise<ValidationResult> {
    let injector = Injector.resolveAndCreate([HTTP_PROVIDERS]);
    let http = injector.get(Http);
    let alreadyExists: boolean;
    if (control.value) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            http.get('/isUserNameUnique/' + control.value).map(response => response.json()).subscribe(result => {
                if (result === false) {
                    resolve({'userAlreadyInUse': true});
                } else {
                    resolve(null);
                }
            });
        }, 1000);
    });
    }
}
 }

Now, when i run, and give a username that already exists in db, the value of 'result' variable i am getting as false, which is expected and correct. But validation error message is not getting displayed. I am able to run and get validation error message for other custom validation functions. I am using Angular 2.0.0-beta.15. Can somebody help me to understand what could be the issue?


Solution

  • if you look into this -

    'userName': ['', Validators.compose([Validators.required, ValidationService.checkUserName])] });
    

    -- you can see I am using both synchronous and asynchronous validations together. When i changed method for checkUserName like 'Validators.composeAsync(ValidationService.checkUserName)' instead of Validators.compose method, error message got displayed.