ngx‑valdemort by Ninja Squad
Simple, consistent validation error messages for your Angular forms.
Tired of writing the same validation logic again, and again?
If you're using Angular forms, you have probably written code like this to display validation errors:
@if (form.controls.email.invalid && (f.submitted || form.controls.email.touched)) {
<div class="invalid-feedback">
@if (form.controls.email.hasError('required')) {
<div>The email is required</div>
}
@if (form.controls.email.hasError('email')) {
<div>The email must be a valid email address</div>
}
</div>
}
Here is a complete small form using that kind of markup.
That's a lot of code and duplications to display appropriate error messages, when the form is submitted or when the input field is touched. And this is only one form, with just two fields.
Sure, we could improve this by adding fields or getters in the component, but doing so for each and every form of the app is cumbersome, error-prone, and can lead to inconsistencies if every developer doesn't use the same technique.
Our solution: ngx-valdemort
Here is how you do the same using ngx-valdemort:
<val-errors controlName="email">
<ng-template valError="required">The email is required</ng-template>
<ng-template valError="email">The email must be a valid email address</ng-template>
</val-errors>
And here is the same complete small form.
This is already much better. The code is much easier to read and write, and the probability of introducing a bug is much smaller than before. But we can do better, and avoid repeating the same error messages over and over.
Consistent error messages? We've got you covered!
By defining a default error message for each type of error once, and only once (typically in the root component), every form can become simpler.
As you can see, you can choose to have very generic error messages (This field is required, as demonstrated on the age example) or, by just specifying the label on the val-errors
component, have specific, but consistent error messages. And if you really need to (like in the error for the minimum age), you can override the default message by the one you want.
By defining the messages in the templates, you can easily internationalize them, use pipes, or HTML formatting.
Easily adapt ngx-valdemort to your preferences
The behavior of ngx-valdemort is configured via a configuration service. The same look and feel can thus be applied globally.
Instead of displaying errors when the control is touched or its form is submitted, the following example uses the service to specify that errors should be shown when the controls are dirty, to add a CSS class on errors to display them in orange rather than red, and to only display one error message per control instead of all of them.
Such a configuration is typically done only once, in the root component (or in a dedicated component inserted in the root component), to ensure that the same configuration applies everywhere.
It works with ngModel
too!
Features
Easy to use
- Minimum markup needed
- Add
val-errors
, and you're set! - Consistent, default error messages
Configurable
- Overriding of default messages for custom error messages
- Access to the error value (min, max, required length, etc.)
- Central configuration service
Customisable
- I18n possible
- HTML in messages possible
- Use of pipes in messages possible
- A fallback message can be specified to handle forgotten errors or to display multiple error types the same way using i18n (see API documentation)
Usable everywhere
- In reactive forms, template-driven forms, or standalone controls
- On controls nested in form groups or form arrays
Free, and open-source.
- MIT license
- The code is available on Github
You convinced me. How to get started?
- import from
ngx-valdemort
- add
ValdemortModule
to the imports of your module, or directly import our standalone components and directives from your components - Use
<val-errors>
,<val-default-errors>
andValdemortConfig
as shown above - ...
- Profit!
We also have an API documentation.
[...]
import { ValdemortModule } from 'ngx-valdemort';
@NgModule({
[...]
imports: [
[...]
ValdemortModule
],
[...]
})
export class AppModule { }