Validating client-side forms with HTML5 AngularJS

It is a good practice to validate submitted data both on the frontend and the backend. It is also good, talking about validation, to distinguish the user experience, from the data integrity conservation from the data integrity conservation. Both are two different responsibilities, potentially for different teams.

We believe the frontend validation has replaced the form-validations that was previously managed by the backend. In a scalable environment where API is decoupled from web content, the validation experiences are now the responsibility of client interfaces that can be multiples (even implemented by third parties) such as websites, mobile websites, mobile apps, and so on.

In this recipe, we will focus on form validation and more specifically on AngularJS form validation.

How to do it…

  1. Let's consider the User Preferences form again. Here is the HTML definition (user-account.html):
    <form name="updateAccount" action="#" ng-class="formSubmitted ? 'submitted':''">
      <fieldset>
        <div class="clearfix span">
          <label for="id" translate> screen.preference.field.username</label>
            <div class="input">
    <input type="text" name="id" placeholder="Username" ng-model="form.id" ng-minlength="4" ng-maxlength="15" readonly required/>
    <span class="text-error" ng-show="formSubmitted && updateAccount.id.$error.required" translate>   error.webapp.user.account.username.required</span>
            </div>
    <label for="email" translate> screen.preference.field.email</label>
          <div class="input">
    <input type="email" name="email" placeholder="Email" ng-model="form.email"/>
    <span class="text-error" ng-show="formSubmitted && 
      updateAccount.email.$error" translate>error.webapp.user.account.email</span>
          </div>
    <label for="password" translate> screen.preference.field.password</label>
          <div class="input">
    <input type="password" name="password" ng-minlength="5" placeholder="Please type again" ng-model="form.password" required/>
    <span class="text-error" ng-show="formSubmitted && updateAccount.password.$error.required" translate>   error.webapp.user.account.password.type.again</span>
    <span class="text-error" ng-show="formSubmitted && updateAccount.password.$error.minlength" translate>   error.webapp.user.account.password.too.short</span>
    </div>   
    <label for="fullname" translate>   screen.preference.field.full.name</label>
            <div class="input" >
    <input type="text" name="fullname" placeholder="Full name" ng-model="form.fullname"/>
            </div>
    <label for="currencySelector" translate>   screen.preference.field.preferred.currency</label>
            <div class="input">
    <select class="input-small"  id="currencySelector" ng-model="form.currency" ng-init="form.currency='USD'" ng-selected="USD" ng-change="updateCredit()">
            <option>USD</option><option>GBP</option>
            <option>EUR</option><option>INR</option>
            <option>SGD</option><option>CNY</option>
            </select>
            </div>
    <label for="currencySelector" translate>   screen.preference.field.preferred.language</label>
            <div class="input">
          <div class="btn-group">
    <button onclick="return false;" class="btn" tabindex="-1"><span class="lang-sm lang-lbl" lang="{{form.language | lowercase}}"></button>
    <button class="btn dropdown-toggle" data-toggle="dropdown" tabindex="-1">
            <span class="caret"></span>
            </button>
           <ul class="dropdown-menu">
    <li><a href="#" ng-click="setLanguage('EN')"><span class="lang-sm lang-lbl-full" lang="en"></span></a></li>
    <li><a href="#" ng-click="setLanguage('FR')">  <span class="lang-sm lang-lbl-full" lang="fr"></span></a></li>
            </ul>
            </div>
            </div>
         </div>
      </fieldset>
    </form>
  2. The JavaScript side of things in the controller of account_management.js includes two referenced functions and four variables to control form validation and its style:
      $scope.update = function () {
          	$scope.formSubmitted = true;
          if(!$scope.updateAccount.$valid) {
           return;
      }
    httpAuth.put('/api/users', JSON.stringify($scope.form)).success(
        function(data, status, headers, config) {
          httpAuth.setCredentials(
            $scope.form.id, $scope.form.password);
            $scope.updateSuccess = true;
            }).error(function(data,status,headers,config) {
              $scope.updateFail = true;
              $scope.updateSuccess = false;
    $scope.serverErrorMessage = errorHandler.renderOnForms(data);
        });
     };
        $scope.setLanguage = function(language) {
        $translate.use(language);
        $scope.form.language = language;
       }
    
       //Variables initialization
       $scope.formSubmitted = false;
       $scope.serverErrorMessage ="";
       $scope.updateSuccess = false;
       $scope.updateFail = false;

    Two CSS classes have been created to render properly errors on fields:

    .submitted  input.ng-invalid{
      border: 2px solid #b94a48;
      background-color: #EBD3D5;!important;
    } 
    .submitted .input .text-error {
      font-weight:bold;
      padding-left:10px;
    }
  3. If you try to enter a wrong e-mail or if you try to submit the form without entering your password, you should observe the following validation control:
    How to do it…

How it works...

AngularJS provides tools to set up a client-side form validation. As usual with AngularJS, these tools integrate well with modern HTML5 techniques and standards.

HTML5 forms provide a native validation that can be defined using tags and attributes on the different form elements (input, select…) to set up a basic field validation (max-length, required…)

AngularJS completes and extends fluently these standard definitions to make them interactive and responsive from the beginning and with no overhead.

Validation-constraints

Let's have a closer look at the available validation-options that can be placed on form controls.

Required

An input field can be tagged as required (HTML5 tag):

<input type="text" required /> 

Minimum/maximum length

The ng-minlength directive can be used to assert that the number of entered characters matches a given threshold:

<input type="text" ng-minlength="3" /> 

Similarly, ng-maxlength drastically limits the number of entered characters to a maximum:

<input type="text" ng-maxlength="15" /> 

Regex pattern

The ng-pattern directive is often used to make sure that the entered data matches a predefined shape:

<input type="text" ng-pattern="[a-zA-Z]" />

Number/e-mail/URL

Those HTML5 input types are handled by AngularJS to be constrained within the format they represent:

<input type="number" name="quantity" ng-model="form.quantity" />
<input type="email" name="email" ng-model=" form.email" />
<input type="url" name="destination" ng-model=" form.url" />

Control variables in forms

AngularJS publishes properties on the containing $scope to match the form state in the DOM. This makes the JavaScript form validation very easy to control errors and to render the state.

These properties are accessible from the following structure:

  formName.inputFieldName.property

Modified/Unmodified state

This state can be assessed using the following properties:

formName.inputFieldName.$pristine;
formName.inputFieldName.$dirty;

Valid/Invalid state

This valid state of a form can be assessed in regards to the defined validation for a field or globally:

formName.inputFieldName.$valid;
formName.inputFieldName.$invalid;
formName.$valid;
formName.$invalid;

Errors

After the validity assessment that we have defined previously, more information about what went wrong can be extracted from the $error property:

myForm.username.$error.pattern
myForm.username.$error.required
myForm.username.$error.minlength

The $error object contains all about the validations of a particular form and reflects whether those validations are satisfactory or not.

Form state transclusions and style

As often with AngularJS, transclusions are proceeded to bind the DOM state with the scope. Thus, the form state and the control state are reflected in real time with CSS classes. These CSS classes can obviously be defined/overridden, so that a global validation style can be defined:

input.ng-invalid {
  border: 1px solid red;
}
input.ng-valid {
  border: 1px solid green;
}

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset