3

Basically I have created user service that has getUserByAlias method in it. For testing purpose it doesn't do anything but prints out string. I have been following video tutorial and in tutorial he basically shows that you need to make sure that service is imported, then included in @component, then included in constructor. So my files looks something like this:

create-account.component.ts

import { Component, OnInit, NgModule, Injector, Injectable } from '@angular/core';
import { FormBuilder, FormControl, Validators, FormArray, FormGroup, AbstractControl, ValidatorFn, AsyncValidator, AsyncValidatorFn, ValidationErrors, NG_ASYNC_VALIDATORS } from '@angular/forms';
import { faCheck } from '@fortawesome/free-solid-svg-icons';
import { Observable } from 'rxjs';
import { UserService } from '../user.service';




const passwordValidator: ValidatorFn = (fg: FormGroup): ValidationErrors | null => {
    var pw =  fg.get('password');
    var pw2 =  fg.get('passwordre');
    if(pw2.value.length == 0){
        return null
    }
    if(pw && pw2 && pw.value !== pw2.value){
        pw2.setErrors({'passNoMatch': true});
        pw2.markAsTouched();
        return { 'passNoMatch': true };
    }else{
        pw2.setErrors(null);
        return null;
    }
}

const username: ValidatorFn = (control: FormControl): ValidationErrors | null => {
    var alias = control
    if(alias && /^\w+$/.test(alias.value)==false){//if not only numbers and letters
        return { 'illegalChars': true };
    }else if(alias && /^\d+$/.test(alias.value)==true){//If only numbers
        return { 'onlyNumbers': true };
    }else{
        alias.setErrors(null);
        return null;
    }
}


@Component({
    selector: 'app-create-account',
    templateUrl: './create-account.component.html',
    styleUrls: ['./create-account.component.scss'],
    providers: [UserService]
})

export class CreateAccountComponent{
    faCheck = faCheck
    constructor( private fb: FormBuilder, private userService: UserService) {
        this.userService.getUserByAlias('test') 
    }


    checkUsername(control: FormControl): Promise<any> | Observable<any>{
        this.userService.getUserByAlias(control.value)  
        const promise = new Promise<any>((resolve, reject) =>{
            //const user = new UserService();
            setTimeout(()=>{
                if(control.value === 'test'){
                    resolve({usernameTaken: true})
                }else{
                    resolve(null)
                }
            },1500)
        })

        return promise;
    }


    usernameCtrl =  this.fb.control('', [
        Validators.required,
        Validators.minLength(4),
        username
    ], this.checkUsername)
    emailCtrl =  this.fb.control('', [
        Validators.required,
        Validators.email
    ])
    passwordCtrl =  this.fb.control('', [
        Validators.required,
        Validators.minLength(5)
    ])
    passwordreCtrl =  this.fb.control('', [
        Validators.required,
        Validators.minLength(5)
    ])

    newAccountForm = this.fb.group({
        username: this.usernameCtrl,
        email: this.emailCtrl,
        password: this.passwordCtrl,
        passwordre: this.passwordreCtrl
    },{ validator: passwordValidator})
}

user.service.ts

import { Injectable } from '@angular/core';
@Injectable({
    providedIn: 'root',
})

export class UserService {
    getUserByAlias(alias: any){
        console.log(alias)
        return alias
    }
}

When input triggers checkUsername I get error: ERROR TypeError: Cannot read property 'userService' of undefined. I called this.userService.getUserByAlias('test') inside the constructor and it printed out to console what it needed. So I assumed, that it doesn't work because it has something to do being called inside custom validator. Why doesn't it work inside validator? and how can I make it work?

user1203497
  • 507
  • 3
  • 11
  • 18

1 Answers1

9

The reason is because the context of this is lost.

To remedy this, you can use the bind function, like so:

    usernameCtrl =  this.fb.control('', [
        Validators.required,
        Validators.minLength(4),
        username
    ], this.checkUsername.bind(this));

This will bind the correct context to that function to ensure it works

hochitom
  • 362
  • 1
  • 3
  • 10
user184994
  • 17,791
  • 1
  • 46
  • 52