Reputation: 1605
I have recreated the issue here
https://stackblitz.com/edit/angular-custom-validator-issue
You can fork the setup (top right) and then edit as you please
Basically I am trying to create a custom validator in my reactive form setup that takes the value of the form input and sends off an http request to the Datamuse API that counts the number of syllables within a string. Then depending on the response result I return either an error or success. I have followed the angular docs but my solution is having problems with the http call, which I beleive is something to do with the call stack order. So I need help on how I can achieve this, I think it will help me alot in understanding Angular a bit better.
import { Component, ElementRef } from '@angular/core';
import { FormControl, FormBuilder, FormGroup, Validators, AbstractControl } from '@angular/forms';
import { VERSION } from '@angular/material';
import { SyllableCountValidator } from './syllable-count.service';
@Component({
selector: 'material-app',
templateUrl: 'app.component.html'
})
export class AppComponent {
version = VERSION;
public poemForm: FormGroup;
constructor(private fb: FormBuilder, private scv: SyllableCountValidator) {
this.createForm();
}
//ERRORS APPEAR IN CONSOLE after INPUT into 'input text' in the dom
// 1. create form group with entry inputText. Initialise it with no value
// and set the validation to a custom validator called 'count' that is
// located in the 'private scv: SyllableCountValidator' service
// go to syllable-count.service file to see next steps
createForm() {
this.poemForm = this.fb.group({
inputText: ['', [this.scv.count]],
});
}
}
import { ValidatorFn, AbstractControl, FormControl } from '@angular/forms';
import { forEach } from '@angular/router/src/utils/collection';
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class SyllableCountValidator {
constructor(private http: HttpClient) {}
// 2. create http request to datamuse API that returns a syllable
// count repsonse for requested text
public requestCount(text): Observable<Object> {
return this.http.get(`https://api.datamuse.com/words?sp=${text}&md=s`) as Observable<Object>;
}
// 3. on any input into the formControl 'inputText' this will fire
public count(control: FormControl) {
// 4. split the string received from the fromControl
// 'textInput' into an array
const arrayOfStrings = control.value.split(' ');
// 5. define empty text variable
let text = '';
// 6. loop through step 3. arrayOfStrings and concatonate into
// correct format for http call and push to text variable in step 4.
const pushToText = Array.prototype.forEach.call(arrayOfStrings, function(word) {
text = `${text}+${word}`;
});
// 7. trim first character of text variable in step 4. to remove
// unessecary '+' character
const trimmedText = text.substr(1);
// 8. call requestCount() in step 2. and return validation result
if (trimmedText) {
const validateSyllables = this.requestCount(trimmedText).subscribe((response) => {
// 8.1.1 if syllable count is greater than 5 return error
// of number of syllables it is greater by
if ( response[0].numSyllables > 5 ) {
return {
error: 5 - response[0].numSyllables
}
// 8.1.2 if syllable count is less than 5 return error
// of number of syllables it is less by
} else if ( response[0].numSyllables > 5 ) {
return {
error: 5 - response[0].numSyllables
}
// 8.1.3 if syllable count equals 5 return validation
// success as required by angular of 'null'
} else if ( response[0].numSyllables == 5 ) {
return null;
}
});
// 9.2. return validation result
return validateSyllables;
}
}
}
Upvotes: 0
Views: 6408
Reputation: 9235
You have issue with 'this' that is not pointing to the proper scope.
"Easy" fix is to use fat arrow function in your service provider this way to ensure 'this' is pointing at the service provider:
instead of:
public count(control: FormControl) {
do:
public count = (control: FormControl) => {
Now your code still needs other issues addressed (like parsing of the response object is not valid).
Upvotes: 3