3

I am trying to create a async custom validator to check if a username already exist in a signup form. I have created a service class which calls the Web API (as below) to check the unique user name.

I also created a async custom validator which suppose to call the service and perform the validation. However I am stuck trying to understand how to inject the service into the validator. The service also get injected with Http.

Anyone has any idea how this validation can be done properly?

-Alan-

Custom Validator

export class UserNameValidators {
    static shouldBeUnique(control: FormControl) {
           ....
           //Need to call the Signup service here
        }
    }

Service

@Injectable()
export class SignUpService
{
        constructor(private http: Http) {

          }
shouldBeUnique(username: string): Observable<boolean> {
        let headers = new Headers();
        headers.append('Content-Type', 'application/x-www-form-urlencoded');
        let options = new RequestOptions({ headers: headers });

               return this.http.post('localhost/authentication/api/accounts/user/' + username, '', options)
            .map((response: Response) => {
                let result = response.toString();
                if (result === 'true')
                    return true

                return false;
            })
            .catch((error: any) => {
                if (error.status === 400) {
                    var cleandata = error._body
                        .replace(/\\n/g, "\\n")
                        .replace(/\\'/g, "\\'")
                        .replace(/\\"/g, '\\"')
                        .replace(/\\&/g, "\\&")
                        .replace(/\\r/g, "\\r")
                        .replace(/\\t/g, "\\t")
                        .replace(/\\b/g, "\\b")
                        .replace(/\\f/g, "\\f");

                    cleandata = cleandata.replace(/[\u0000-\u001F]+/g, "");

                    return Observable.throw(new Error("Unknown Error"));
                }

            });
    }
}

Update

App.Module

@NgModule({
    imports     : [BrowserModule, HomeModule, SignupModule,signupRouting, routing],
    declarations: [AppComponent],
    providers   : [AuthService, AuthGuard, SignupService],
    bootstrap   : [AppComponent]
})

Custom Validator

export class UserNameValidators {

    constructor(private service: SignupService) { }

    shouldBeUnique(control: FormControl) {
        return new Promise((resolve, reject) => {

            this.service.shouldBeUnique(control.value).subscribe(
                data => {
                    if (data.length == 0 || data.length == 1) {
                        resolve(null);
                    } else {
                        resolve({ shouldBeUnique: true });
                    }
                },
                err => {
                    resolve({ shouldBeUnique: true });
                }
            )
        });

    }
}

Signup.component

export class SignupComponent implements OnInit {
    form: FormGroup;
    signedUp: boolean = false;
    error = '';

    constructor(private fb: FormBuilder, private router: Router, private signupService: SignupService) { }

    ngOnInit() {
        this.form = this.fb.group({
            firstname: ['', Validators.required],
            lastname: ['', Validators.required],
            username: ['', Validators.compose([Validators.required, UserNameValidators.notValidEmail]), new UserNameValidators(this.signupService).shouldBeUnique],

            password: ['', Validators.compose([Validators.required, UserNameValidators.cannotContainSpace])],
            confirmpassword: ['', Validators.compose([Validators.required, UserNameValidators.cannotContainSpace])]
        }, { validator: this.matchingPasswords('password', 'confirmpassword') });
    }
}
Alan B
  • 2,219
  • 4
  • 32
  • 62

1 Answers1

2

However I am stuck trying to understand how to inject the service into the validator

I assume that is your question:

You need to register your service as a provider in your app.module:

@NgModule({ 
    // imports, etc
    providers: [
    appRoutingProviders,
    SignUpService]})

Decorate your service with @Injectable():

@Injectable()
export class SignUpService {
// your service...

Add a constructor to your validator that takes SignUpService:

constructor(private signUpService: SignUpService)
{

}
  • changed based on your answer (the question is edited) , however, it looks like the service is not properly injected. It complaint "EXCEPTION: Cannot read property 'service' of undefined" – Alan B Oct 04 '16 at 05:57