Form and validation are fundamental in website. Angular provide easy way to handle validation in form but we can still simplify more validation work with directive.
In this post, I’ll show you how easily show validation error message without *ngIf and long expression.
I assume you’ve already familar with Angular, I suggest you read these topic if you don’t know them.
Showing message to the user makes our code looks ugly. For example
Before add validation message
After add validation message
Ewww. it’s so mess now. 😵
So I’m trying to get rid of duplicated code with directive magic. Here it’s what I achieve.
It does looks a lot cleaner. 😻
This is achieved by 2 directives. invalidmessage and invalidType.
invalidmessage directive receive form control by name and set visible of hosted element based on the form control’s error.
Here’s the code of invalidmessage directive.
Don’t worry, I will explain code soon.
First, I inject
ControlContainer for get
Formgroup instance from nearest parent’s injector (it’s
myForm in the above example ).
Now we can easily get from control by name (eg,
this.form.get('yourcontrolname') ). 😎
FormControl instance can get value, error and so on. Actually it’s just form control that you use in ReactiveForm. For example,
setVisible() method for set hosted element visble when the control is valid and hidden when it’s not.
Showing error message at first is really bad (Many Ux website told that) so it’d make user less grumpy if it just show when user interact with control or click submit button already. I check that with
this.hasSubmitted in the above .
setVisible() method will be called when value of control is changed and when user click submit button.
Observable.of , it’ll emit immediately so
setVisible() will be called at initial.
formSubmit$ is Observable that emit when form is submitted. It’ll set
match method for invalidType directive to call for checking if it match control’s error type.
this.control.errors is object whose propery name is error type. Say, form control has required and email validations and user break it. FormControl
errors object will be like this.
You’ll see how it’s used in the next section.
This directive is for set visible of host element based on error type of control which control difined in invalidmessage directive.
As you may notice in the above example,
*invalidmessage . There’s asterisk prefix. It’s called Stuctural directive. For short, Stuctural directive will create
ng-template surrounding host element which make host element won’t be rendered until you explicitly render with
Let code explian itself
This directive is injected with 3 dependencies — InvalidmessageDirective, TemplateRef and ViewContainerRef.
TemplateRef and ViewContainerRef are for create and remove host element(which it’s error message).
Angular inject instance of InvalidmessageDirective that is nearest parent injector.
<p *invalidType="'required'">Please provide name</p>
InvalidTypeDirective which is on
<p> can get instance of invalidmessageDirective (which is on
<div>) by injecing InvalidmessageDirective in invalidTypeDirective as we did above.
So invalidType directive can use property and method of invalidmessage directive instance.
invalidmessage’s match method take a type of error by argument(which it’s defined with
type property) and check if error object has the specified error type.
If invalidmessage’s match return true, view container will create view from
ng-template surrounding hosted element) and view container will clear when it’s false. In layman’s term, invalidType directive show and remove host element based on return value of invalidmessage’s match method.
It need to check if view container hasn’t created by checking
hasView property so it won’t create repeatly.
setVisible() is called when invalidmessage’s controlValue$ emit(control value change and user click submit button).
That’s all. These two directives can simplify our form validation. It’s maybe not perfect but it can give you an idea.
If you have any question or suggestion, please comment below.