Introduction
After set constraints for input we should consider displaying error-messages. There are three angular ways discussed in this tips: ngShow
, ngIf
and ngMessages
.
UPDATE: My project is based on Angular v1.3.X. Anuglar has been updated to v1.4.X, the usage of ngMessages
has been changed a lot!
Background
Angular offers several solutions, or rather directives, to handle this task, the popular forms are ngShow
(begins in Angular v1.0.x), ngIf
(begins in Angular v1.2.x) and ngMessages
(begins in Angular v1.3.x).
We have discussed about the input constraints and validations in last post (constraints).
For following comparison we use the year’s input field as an example:
<code><label>Year: <input type="number" name="year" ng-min="1459" ng-max="{{currentYear}}" ng-model="book.year" ng-required="true" /></label>
</code>
The input of ngModel book.year
is required, the value must be a number and the number should not less than 1459 or more than 2015 (current year as a number).
Using the code
The ngShow
modifies CSS class onto the element, and the content in this element will be loaded together with the whole web page.
Display error-messages using ngShow
:
<code><input type="number" name="year" ng-model="book.year" ng-min="1459" ng-max="{{currentYear}}" ng-required="true" />
<span ng-show="bookInfo.year.$error.required">Year is Required.</span>
<span ng-show="bookInfo.year.$error.number">Not valid number.</span>
<span ng-show="bookInfo.year.$error.min">The publish year should be after 1459.</span>
<span ng-show="bookInfo.year.$error.max">The publish year should be before {{currentYear}}.</span>
</code>
When the page is loaded, all span
will also be loaded, and we can see its content “Year is required.” existed just because Angular detects that currently the input field is empty or rather the value of bookInfo.year.$error.required
is true, so the content inside of span
should appear. After we put some letters to the field, “Year is required.” will be hidden.
The behavior of span
with attribute ng-show="bookInfo.year.$error.number"
, ng-show="bookInfo.year.$error.min"
and ng-show="bookInfo.year.$error.max"
are same as the span
with attribute ng-show="bookInfo.year.$error.required
.
Please notice that the span
is only be hidden but still exists in the DOM. This is exactly the different part between ngShow
and ngIf
.
The ngIf
directive modifies real DOM tree. Display error-messages using ngIf
:
<code><input type="number" name="year" ng-model="book.year" ng-min="1459" ng-max="{{currentYear}}" ng-required="true" />
<span ng-if="bookInfo.year.$error.required">Year is Required.</span>
<span ng-if="bookInfo.year.$error.number">Not valid number.</span>
<span ng-if="bookInfo.year.$error.min">The publish year should be after 1459.</span>
<span ng-if="bookInfo.year.$error.max">The publish year should be before {{currentYear}}.</span>
</code>
When the page is loaded, we can see its content “Year is required.” existed. It looks like using ngShow
because currently the value of bookInfo.year.$error.required
is true, ngIf
made a clone of span
and inserted it into DOM, so the content inside of span
is shown. After we put some letters to the field, the value of bookInfo.year.$error.required
would be false, and ngIf
will remove the span
so that “Year is required.” will disappear.
The behavior of span
with attribute ng-if="bookInfo.year.$error.number"
, ng-if="bookInfo.year.$error.min"
and ng-if="bookInfo.year.$error.max"
are same as the span
with attribute ng-if="bookInfo.year.$error.required"
.
<font color="#111111" face="Segoe UI, Arial, sans-serif"><span style="font-size: 14px;">Different between ngIf and ngShow: </span></font>ngIf
controlls part of the DOM elemente while ngShow
changes the CSS property.
On the other hand, once all directives matching DOM element have been identified, the Angular compiler will sort the directives by their priority. ngIf
has one of the hightest priority (level 600 by default), it will run first before all other lower prioritised directives. And if we use it instead of ngShow
, the UI will be well speeded up1 .
The ngMessages
, which contains two directives ng-messages
and ng-messages-include
, is a new Angular module published by Angular version 1.3.x, we can now collect all errors into another template, make the project more structured. (angular-messages.js must be included first, before we want to use it)
Display error-messages using ngMessages
:
<code><!-- partials/createBook.html -->
<label>Year: <input type="number" name="year" ng-model="book.year" ng-min="1459" ng-max="{{currentYear}}" ng-required="true" /></label>
<span ng-messages="bookInfo.year.$error" ng-messages-include="partials/errorMessages/errorYear.html"></span>
<!-- partials/errorMessages/errorYear.html -->
<span class="errors">
<span ng-message="required">Year is Required.</span>
<span ng-message="number">The YEAR should only be number like "1459" here.</span>
<span ng-message="min">The publish year should be after 1459</span>
<span ng-message="max">The publish year should be before {{currentYear}}</span>
</span>
</code>
The DOM behavior by using ngMessages
is similar as by using ngIf
. In our web application we use ng-messages-include
and create a single errorYear.html file specific with all of the messages for the possible errors. This is the pro-point comparing with ngIf
.