Constraint Validation API

The most robust way to validate a form field in the browser is to write a validation function. You can use validation functions in conjunction with the Constraint Validation API to trigger built-in validation behavior.

But there is a catch, and it is not a small one: The Constraint Validation API has poor support in Apple’s Safari browser.

Despite this oversight, it is important to write code that targets standard behavior and then add a JavaScript library that adds support for noncompliant browsers. (You can read more about this in the section called For the More Curious: The Webshims Library at the end of this chapter.)

Suppose your coffee truck is only for employees of your company, so you want to make sure that the customer is an employee. One way to do this would be to ensure that the email address that is submitted is from your company’s domain.

You could use a pattern attribute for your emailAddress field. But this problem is a good one for learning the Constraint Validation API. (Also, after you work through the next chapter, you could expand beyond a simple email domain check and query a remote server to find out whether the email address actually exists.)

Create a new file, scripts/validation.js, to hold your validation functions. Add a <script> tag in index.html for your new module.

...
      </div>
    </section>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"
      charset="utf-8"></script>
    <script src="scripts/validation.js" charset="utf-8"></script>
    <script src="scripts/checklist.js" charset="utf-8"></script>
    <script src="scripts/formhandler.js" charset="utf-8"></script>
    <script src="scripts/datastore.js" charset="utf-8"></script>
    <script src="scripts/truck.js" charset="utf-8"></script>
    <script src="scripts/main.js" charset="utf-8"></script>
  </body>
</html>

Save index.html. In validation.js, add an IIFE module that creates an empty object literal, assigns it to a variable named Validation, and then exports that variable to the App namespace.

(function (window) {
  'use strict';
  var App = window.App || {};

  var Validation = {

  };

  App.Validation = Validation;
  window.App = App;
})(window);

Your new Validation module will only be used for organizing functions, so it does not need to be a constructor.

Add a method called isCompanyEmail. This method will test an email address against a regular expression and return true or false. (Feel free to change the email domain specified.)

(function () {
  'use strict';
  var App = window.App || {};

  var Validation = {
    isCompanyEmail: function (email) {
      return /[email protected]$/.test(email);
    }
  };

  App.Validation = Validation;
  window.App = App;
})(window);

You created a literal regular expression by putting a pattern between the forward slashes, //. Inside the slashes, you specify a string that consists of one or more characters (.+), followed by “@bignerdranch.com” – you also used a backslash to indicate that the period in bignerdranch.com should be treated as a literal period. (Normally, a period in a regular expression is a wildcard that matches any character.) The “$” at the end of regular expression means that “@bignerdranch.com” should be at the end of the string – there should be no more characters that appear after it.

This regular expression is an object and has a test method. You can pass a string to the test method, and it will return a Boolean – true if the regular expression matches the string and false if not. (For a list of other regular expression methods, see developer.mozilla.org/​en-US/​docs/​Web/​JavaScript/​Reference/​Global_Objects/​RegExp.)

Test your App.Validation.isCompanyEmail function on the console (Figure 12.3).

Figure 12.3  Testing App.Validation.isCompanyEmail on the console

Testing App.Validation.isCompanyEmail on the console

You now have a function that can check for valid email addresses. The next thing to do is to connect it to the form.

Listening for the input event

When should you use this function? There are several events that the input field could trigger while a user is filling out the form. One occurs as the user types each character. Another is when the user removes focus from the field. Or you could run the function when the form is submitted.

The Constraint Validation API requires that invalid fields be marked prior to submission. If any fields are invalid, the browser stops short of triggering the submit event. So doing the check on submit is too late.

The event triggered when the user removes focus from a field is known as a blur event. It is not a good choice for validation, either. Suppose the user’s cursor is in the email input, so that field has focus. If the user then presses the Return key, this would trigger form submission, but the blur event would not be triggered and any validation tied to it would not be performed.

So the validation check will need to happen as the user enters each character. Update the FormHandler module in formhandler.js with an addInputHandler prototype method. It should add a listener for the input event of the form. Like the addSubmitHandler method, it should accept a function argument.

...
  FormHandler.prototype.addSubmitHandler = function (fn) {
    ...
  };

  FormHandler.prototype.addInputHandler = function (fn) {
    console.log('Setting input handler for form');
  };

  App.FormHandler = FormHandler;
  window.App = App;
...

Attach the listener for the input event using jQuery’s on method. Make sure to use the event delegation pattern to filter out events created by anything but the [name="emailAddress"] field.

...
  FormHandler.prototype.addInputHandler = function (fn) {
    console.log('Setting input handler for form');
    this.$formElement.on('input', '[name="emailAddress"]', function (event) {
      // Event handler code will go here
    });
  };

  App.FormHandler = FormHandler;
  window.App = App;
...

Inside the event handler, extract the value of the email field from the event.target object. Then console.log the result of running addInputHandler’s function argument fn and passing it the value of the email field.

...
  FormHandler.prototype.addInputHandler = function (fn) {
    console.log('Setting input handler for form');
    this.$formElement.on('input', '[name="emailAddress"]', function (event) {
      // Event handler code will go here
      var emailAddress = event.target.value;
      console.log(fn(emailAddress));
    });
  };

  App.FormHandler = FormHandler;
  window.App = App;
...

Save formhandler.js.

Associating the validation check with the input event

In main.js, import Validation from the App namespace and assign it to a local variable.

...
  var Truck = App.Truck;
  var DataStore = App.DataStore;
  var FormHandler = App.FormHandler;
  var Validation = App.Validation;
  var CheckList = App.CheckList;
  var myTruck = new Truck('ncc-1701', new DataStore());
...

With the Validation object imported, you can connect it to FormHandler’s new addInputHandler method.

At the end of main.js, pass Validation.isCompanyEmail to the addInputHandler method of the formHandler instance:

...
  formHandler.addSubmitHandler(function (data) {
    myTruck.createOrder.call(myTruck, data);
    checkList.addRow.call(checkList, data);
  });

  formHandler.addInputHandler(Validation.isCompanyEmail);

})(window);

Save and reload. Fill out the email field and see what appears on the console. As you type a valid email address, the console will show a number of false results, printed by the console.log(fn(emailAddress)); line in FormHandler.prototype.addInputHandler. When you have finished typing a valid email address, you will see true printed in the console (Figure 12.4).

Figure 12.4  Logging the email validation check

Logging the email validation check

Your validation function is run each time a character is entered (or removed) from the email field. When you have confirmed that it is correctly checking your input, you can use it to show a custom error message.

Triggering the validity check

Now that you can reliably test that the email address is from your company’s domain, you should notify the user if the validation fails. You will use the setCustomValidity method for the event.target to mark it as invalid.

In formhandler.js, remove the console.log statement and replace it with a variable for a warning message and an if/else clause. If the fn(emailAddress) call returns true, clear the custom validity of the field. If it returns false, assign the message variable to a string with the warning message and set the custom validity to message.

...
  FormHandler.prototype.addInputHandler = function (fn) {
    console.log('Setting input handler for form');
    this.$formElement.on('input', '[name="emailAddress"]', function (event) {
      var emailAddress = event.target.value;
      console.log(fn(emailAddress));
      var message = '';
      if (fn(emailAddress)) {
        event.target.setCustomValidity('');
      } else {
        message = emailAddress + ' is not an authorized email address!'
        event.target.setCustomValidity(message);
      }
    });
  };
...

You passed in the error message that should be shown to the user. If there is no error, you still have to call setCustomValidity, but with an empty string as the argument. This has the effect of marking the field as valid.

The validation check that occurs as you type only marks the field as valid or invalid. It does not display the error message. When you press the Submit button, the browser checks for invalid fields and displays the validation message if it finds any.

To try it out, submit the form after entering an email address that does not match the domain. Right after you press the Submit button, you should see your custom validation message appear as a warning next to the field (Figure 12.5).

Figure 12.5  Only valid email addresses allowed!

Only valid email addresses allowed!
..................Content has been hidden....................

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