I'm having a little trouble understanding how I need to create a Custom Directive in Angular. I have an input field and a user needs to enter a string of characters, but it needs to check that the string doesn't contain certain substrings. So far I've go this function:
checkInvalidStrings(value, invalidValues) {
let isKbWalk;
let amount = [];
invalidValues.forEach(string => {
if (value.indexOf(string) > -1) {
amount.push(string);
}
})
if (amount.length < 4) {
isKeyboardWalk = false;
} else {
isKbWalk = true;
}
return isKbWalk;
}
I can run this in ngModel change in the component file and it works perfectly, the problem I'm having is that I want to link it with the form validation, so if it returns false, I want it to be valid, if it returns true, I want it to be invalid. I believe I need to create a custom validator directive for this, but I'm having some trouble with it. I guess what I'm asking is how do I take the function above so that I can implement it as a directive to determine if it's valid or not? I'm using template driven forms because that is what the application has been built with and it's simpler at this point to stay consistent than to change to Reactive Forms.
Generally I want to be able to do something on the input like this, where kbWalk is the directive which checks the input field for the invalid strings:
<input [(ngModel)]="data.newValue" name="newValue" #newValue="ngModel" required kbWalk>
So far I have everything imported into the app.module file but the validation isn't working correctly, here's the set up for my directive:
import { Directive, forwardRef, Attribute } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
import { Invalid } from './invalidStrings';
@Directive({
selector: '[kbWalk][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: KeyboardWalkValidator, multi: true }
]
})
export class KeyboardWalkValidator implements Validator {
invalidStrings = Invalid.strings;
constructor() { }
validate(c: AbstractControl): { [key: string]: any } {
return null;
}
}
Thanks for your help!
SOLVED:
import { Directive, forwardRef, Attribute, Input } from '@angular/core';
import { Validator, FormControl, NG_VALIDATORS } from '@angular/forms';
import { Invalid } from '../components/common/Invalid';
@Directive({
selector: '[isKeyboardWalk][formControlName],[isKeyboardWalk][formControl],[isKeyboardWalk][ngModel]',
providers: [ { provide: NG_VALIDATORS, useExisting: KeyboardWalkValidator, multi: true }
]
})
export class KeyboardWalkValidator implements Validator {
invalid = Invalid.array;
validate(c: FormControl): { [key: string]: any } {
const val = c.value;
return this.checkInvalidStrings(val) ? {'isKeyboardWalk': true} : null;
}
checkInvalidStrings(value) {
// code for checking invalid value
}
}
Then in the view I just use the isKeyboardWalk Directive:
<input type="text" isKeyboardWalk/>
My problem was in understanding that the value being passed into the validate function is actually the value from the form, so I could just use that value to run inside my checkInvalidStrings() Function and it works fine. If you guys are have a choice I would suggest using Reactive Forms and implementing the solution in the comment below which is pretty straight forward as well and helped me understand a little more.