Reputation: 1032
I am using angular4-material-table . there I tried to add custom input validation I have created seperate validator service there I called custom function to hit my api based on api result it will throws input valid or not.
here is my code can anyone suggest me what mistake I made,
import { Injectable } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { ValidatorService } from 'angular4-material-table';
import { AbstractControl } from '@angular/forms';
import { ApiCallService } from 'api.service';
@Injectable()
export class MatTableValidatorService implements ValidatorService {
constructor( private api_call: ApiCallService) {
}
getRowValidator(): FormGroup {
return new FormGroup({
'name': new FormControl(null, [Validators.required, this.nameValidator]),
});
}
nameValidator(control: AbstractControl): { [key: string]: boolean } | null {
this.api_call
.api_function(parameter)
.subscribe(data => {
const arrayVal = data.response;
if(arrayVal.length > 0)
{
return {'dnsCheck': true}
}
return null;
});
return null;
}
}
this one returns error : cannot read property of api_call even though I declared it in constructor
and another way:
public nameValidator = (control: AbstractControl) => {
this.api_call
.api_function(parameter)
.subscribe(data => {
const arrayVal = data.response;
if(arrayVal.length > 0)
{
return {'dnsCheck': true}
}
return null;
});
};
this way works but even though input valid or not it always throws error. I have checked output with console seems getting from api is perfectly done. can anyone assist me whats my mistake. Thanks in advance.
A stackblitz example can be seen here.
Upvotes: 1
Views: 306
Reputation: 38094
I am not sure whether it is a reason, however you are not awaiting result of your api call. Your code always return null
. So we need to await result of API call:
async nameValidator(control: AbstractControl): { [key: string]: boolean } | null {
const result = await this.api_call.api_function(parameter);
const arrayVal = result.response;
if (arrayVal.length > 0)
return {'dnsCheck': true}
return null;
}
UPDATE:
You can add custom validator. Forbidden name is Mark
, if you write forbidden name, then input will not save this value:
@Injectable()
export class PersonValidatorService implements ValidatorService {
getRowValidator(): FormGroup {
return new FormGroup({
'name': new FormControl(null, [Validators.required, forbiddenNameValidator()])
});
}
}
export function forbiddenNameValidator(): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} | null => {
const forbidden = 'Mark';
console.log(`forbidden name is `, forbidden);
return (forbidden == control.value) ? {'forbiddenName': {value: control.value}} : null;
};
}
Upvotes: 1
Reputation: 559
Angular Custom Validations contains a different scope and therefor the first example you made did not work.
The second example did work since you used 'arrow function'. Because your custom validation is async, you need to return an observable. Take a look at the following
First option:
nameValidator = (control: AbstractControl): Observable<{ [key: string]: boolean } | null> => {
return this.api_call
.api_function(parameter)
.pipe(
map(
data => {
const arrayVal = data.response;
return arrayVal && arrayVal.length > 0 ? { 'dnsCheck': true } : null
}
)
);
}
Second Options:
this.nameValidator.bind(this) is where the magic happens
getRowValidator(): FormGroup {
return new FormGroup({
'name': new FormControl(null, {
asyncValidators: [this.nameValidator.bind(this)],
validators: [Validators.required],
}),
});
}
nameValidator(control: AbstractControl): Observable < { [key: string]: boolean } | null > {
return this.api_call
.api_function(parameter)
.pipe(
map(
data => {
const arrayVal = data.response;
return arrayVal && arrayVal.length > 0 ? { 'dnsCheck': true } : null
}
)
);
}
Upvotes: 0