Angular: Accessing Class Variables within Custom Validators

Angular’s built-in validators are great (Required, MinLength, MaxLength, etc.), but you’ll often find yourself needing to test unique UI control use cases. Enter custom validators, a powerful way to accomplish this:

validUsernames: AllowedUsername[];

constructor(private fb: FormBuilder,
            private apiService: ApiService) { }

ngOnInit() {
    this.form = this.fb.group({
        // Attach a custom validator to the userName control
        "userName": [this.userName, this.usernameValidator]
        }
    );
}

private usernameValidator(c: AbstractControl): { [key: string]: boolean } {
    // check a property of c, the Control this validator is attached to
    if (c.value === "bad value") {
            // if a bad username is detected, return an error
            return { 'badValueFound': true };
        }
    }

    return null;
}

This works just fine if you only need to test using the properties of the AbstractControl - how about testing for valid usernames via a local array object or by making an HTTP API call?

private usernameValidator(c: AbstractControl): { [key: string]: boolean } {
    // check a property of c, the Control this validator is attached to
    if (this.validUsernames.contains("bad value")
        || this.apiService.isValidUsername("bad value")) {
            // if a bad username is detected, return an error
            return { 'badValueFound': true };
        }
    }

    return null;
}

We get errors, though: both validUsernames and apiService will be undefined. Bummer!

Fortunately, there is a way to access them, not mentioned by the official docs. You must explicitly bind the current class to the validator function:

this.form = this.fb.group({
    "userName": [this.userName, this.usernameValidator.bind(this)]
    }
);

That’s all it takes. Enjoy!

comments powered by Disqus