Displaying error messages on submission with Angular Formly
developmentDisplaying error messages on submission with Angular Formly
Angular Formly in an Angular app I am working on as an alternative to creating Angular forms in HTML. I have found the HTML approach leads to validation and control logic for the form being split between both the HTML (with many ng-if
, ng-show
, ng-required
/ required
and ng-change
directives sprinkled everywhere) and the JavaScript controller for the form.
This makes a consistent architecture for validation and control logic difficult to maintain. It also leads to a lot of duplicated HTML in controller templates and duplicated validation logic everywhere.
Angular Formly provides what I hope will be a reprieve from this mess!
After ripping out a smaller form in my app and reconstructing it in the object literal/functional approach that Angular Formly champions I was able to get a very nice layout with the Angular Formly: Material Templates inspired by Angular Material (which has recently hit v1.0 at the time of this writing).
I needed to customize the way error/validation messages were displayed to the user, with the following requirements.
- Validation UI signaling occurs after an element loses focus and is invalid (red border around the field)
- Validation messages are displayed only after submitting the form with invalid elements, even if they have never had interaction from the user
- These rules should be applied globally instead of per-field or per-form
To meet these requirements I updated my app’s config
function
function config($locationProvider, formlyConfigProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
formlyConfigProvider.extras.errorExistsAndShouldBeVisibleExpression = function($viewValue, $modelValue, scope) {
return (scope.fc.$invalid && scope.form.$submitted);
};
}
By setting the formlyConfigProvider.extras.errorExistsAndShouldBeVisibleExpression
to a function I can determine if the error message should be displayed for each field based on the field’s validity (scope.fc.$invalid
) and the form’s submission status ( scope.form.$submitted
). I also updated my app’s run
function.
function run(formlyValidationMessages) {
formlyValidationMessages.addStringMessage(
'required',
'This field is required'
);
}
Which provides a default error message on all fields that are defined with templateOptions: { required: true }
or with validators: { required: function($viewValue, $modelValue, scope) { ... } }
. I then created a form in my controller template.
<form novalidate ng-submit="vm.onSubmit()">
<formly-form model="vm.model" fields="vm.fields" form="vm.form">
<div class="col col-third">
<div class="row">
<button type="submit" class="btn btn-primary">Save Changes</button>
</div>
</div>
</formly-form>
</form>
The problem was when I submitted the form the Validation UI signaling appeared but the error message was not displayed. When I set breakpoints in app.js
for the errorExistsAndShouldBeVisibleExpression
function I saw that scope.form.$submitted
was always false even after I had just hit the button to submit the form.
The problem was on line one of the above controller.html
. Although I had defined a form on my formly-form
directive I had not specified the form name
attribute on the form
element. The form connected to the formly-form
was not the form I was submitting when pressing the button.
To fix this I added a name attribute to my form
element.
<form novalidate ng-submit="vm.onSubmit()" name="vm.form">
<formly-form model="vm.model" fields="vm.fields" form="vm.form">
<div class="col col-third">
<div class="row">
<button type="submit" class="btn btn-primary">Save Changes</button>
</div>
</div>
</formly-form>
</form>
Now when I submit the form, even if I have not edited any fields, the validation messages will appear for all elements that are required or have any other validation errors.