I created a custom component which have it' own @input()
, @output
and so on. This component has a <input />
field where a user can enter some value.
E.g: <my-component ...></my-component>
I reference it in my html and it works flawlessly. I also created several directives which validate form input data via simple regexps. I can use them in plain input inside a form like:
<input type="text" validator1 validator2 validator3 />
Is there a way to pass one or more of these directive (but also none of them) to my custom component without hardcoding them in the source of the component?
Some kind of ...params
to evaluate?
Thanks in advance for all your help
Valerio
The pattern you're looking for is definitely possible, but not achievable with directives in a sense you're trying to. This is due the fact that Angular is compiled, meaning you cannot not "hard-code" a directive (at least not without doing weird stuff that's not recommended to do in production).
Your component can accept an input named validators
, which should be an array of functions (or instances of a class, if you need it), and then use that to validate.
For example, you can have the following three super-simple validators:
export const required = value => value != null && value != ''
export const minLength3 = value => value == null || value.length > 3
export const maxLength9 = value => value == null || value.length < 9
Your my-component
accepts an array of these validators. For simplicity sake, a validator is actually a predicate of a string. In other words, it is a function with the same signature as three functions above: (value: string) => boolean
. We initialize this input as an empty array, effectively making this the default value in case nothing is passed down to it.
@Input() validators: ((value: string) => boolean)[] = []
In the consumer component's template (the component using my-component
), we now use the component by passing down an array of validators to it.
<my-component [validators]="[required, maxLength9]"></my-component>
Of course, to use them, we have to either DI them or simply instantiate them as members of the component class. To use it with DI, validators would have to be classes (at least as far as versions 5.x.x and below go).
import {required, maxLength9} from '../validators'
export class ConsumerComponent {
public required = requierd
public maxLength9 = maxLength9
}
The my-component
component should, of course, make use of these validators. For example, the following function can be run on each change
or input
or blur
event, depending on when do you want to run the validators.
public validate(value: string): boolean {
let valid: boolean = true
this.validators.forEach(validator => {
const result = validator(value)
valid = valid || result
})
}
You now have better dynamic control of which validators you want to run on the field. You can also change these dynamically during run-time of the application, of course. This comes at the following cost: no tree-shaking of unused validators. Angular compiler can no longer determine which validators are you using, which means that all of them have to be imported in the final bundle of your app, even though some of them might never be used.
You might be interested in reactive forms in Angular. You can read about reactive forms in official documentation, or take a look at Todd Motto's article on reactive forms in Angular, or Reactive Forms in Angular by Pascal Precht on thoughtram.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With