Amaze UI 2.4

JavaScript

Amaze UI styled jQuery plugins and utils.

Form Validator


Based on HTML 5 form validation, form validator uses attributes in HTML 5 to validate the form, such as type, required, pattern, min, max, minlength and maxlength. Form validator can still work like normal H5 validation in the enviroment that don't support JS.

Examples

HTML5 Native Form Validation

If the form is only for HTML5 and don't need control, there is no doubt that the native validation is the best solution, and styles can be controlled using pseudo classes such as :valid and :invalid.

H5 Native Validation
<form action="" class="am-form">
  <fieldset>
    <legend>H5 Native Validation</legend>
    <div class="am-form-group">
      <label for="doc-vld-name-1">Username:</label>
      <input type="text" id="doc-vld-name-1" maxlength="3" pattern="^\d+$" placeholder="Input username here" class="am-form-field" required/>
    </div>
  </fieldset>
</form>

Reference:

JS Form Validation

JS form validation is based on HTML5 form validation:

  • required: Can't be empty;
  • pattern: Test with regular expression. Regular expression for email, url and number are provided by plugin;
  • minlength/maxlength: Maximum length;
  • min/max: Maximum, Minimum of value. Only avaliable in number-type input boxes;
  • minchecked/maxchecked: Maximum, minimum number of checked boxes. Avaliable in checkbox and dropdown. The relative attributes are set in the first element when using checkbox;
  • .js-pattern-xx: Validation rule classes. Rules in regular expression libraries can simply be validated by adding corresponding classes.

Attention:

pattern in HTML5 only validate if the input is legal, which means it can be legal expression or empty. If this value is required, please add required attribute.

<!-- The following validations are equivalent -->
<input type="email"/>

<!-- xx in js-pattern-xx is the key in the pattern library -->
<input type="text" class="js-pattern-email"/>

<input type="text" pattern="^(...email regex...)$"/>
JS Form Validation
<form action="" class="am-form" data-am-validator>
  <fieldset>
    <legend>JS Form Validation</legend>
    <div class="am-form-group">
      <label for="doc-vld-name-2">Username: </label>
      <input type="text" id="doc-vld-name-2" minlength="3" placeholder="At least 3 characters" required/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-email-2">Email: </label>
      <input type="email" id="doc-vld-email-2" placeholder="Input email here" required/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-url-2">URL: </label>
      <input type="url" id="doc-vld-url-2" placeholder="Input URL here" required/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-age-2">Age: </label>
      <input type="number" class=""  id="doc-vld-age-2" placeholder="Between 18 and 120" min="18" max="120" required />
    </div>

    <div class="am-form-group">
      <label class="am-form-label">Favorite fruit: </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Orange" name="docVlCb" minchecked="2" maxchecked="4" required> Orange
      </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Apple" name="docVlCb"> Apple
      </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Pineapple" name="docVlCb"> Pineapple
      </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Mongo" name="docVlCb"> Mongo
      </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Banana" name="docVlCb"> Banana
      </label>
    </div>

    <div class="am-form-group">
      <label>Gender: </label>
      <label class="am-radio-inline">
        <input type="radio"  value="" name="docVlGender" required> Male
      </label>
      <label class="am-radio-inline">
        <input type="radio" name="docVlGender"> Female
      </label>
    </div>

    <div class="am-form-group">
      <label for="doc-select-1">Drowdown</label>
      <select id="doc-select-1" required>
        <option value="">-=Please select one=-</option>
        <option value="option1">Option 1...</option>
        <option value="option2">Option 2.....</option>
        <option value="option3">Option 3........</option>
      </select>
      <span class="am-form-caret"></span>
    </div>

    <div class="am-form-group">
      <label for="doc-select-2">Checkbox</label>
      <select multiple class="" id="doc-select-2" minchecked="2" maxchecked="4">
        <option>1</option>
        <option>2</option>
        <option>3</option>
        <option>4</option>
        <option>5</option>
      </select>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-ta-2">Comment: </label>
      <textarea id="doc-vld-ta-2" minlength="10" maxlength="100"></textarea>
    </div>

    <button class="am-btn am-btn-secondary" type="submit">Submit</button>
  </fieldset>
</form>

Show Prompts

Prompts can be shown using the callback interface of .onValid and onInValid.

See following examples for more details.

Attention: .getValidationMessage(validity) is a new method in v2.3, the former version only have customized information.

Show prompt at the bottom

JS Form Validation
<form action="" class="am-form" id="doc-vld-msg">
  <fieldset>
    <legend>JS Form Validation</legend>
    <div class="am-form-group">
      <label for="doc-vld-name-2">Username: </label>
      <input type="text" id="doc-vld-name-2" minlength="3" placeholder="At least 3 characters" required/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-email-2">Email: </label>
      <input type="email" id="doc-vld-email-2" placeholder="Input email here" required/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-url-2">URL: </label>
      <input type="url" id="doc-vld-url-2" placeholder="Input URL here" required/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-age-2">Age: </label>
      <input type="number" class=""  id="doc-vld-age-2" placeholder="Between 18 and 120" min="18" max="120" required />
    </div>

    <div class="am-form-group">
      <label class="am-form-label">Favorite fruit: </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Orange" name="docVlCb" minchecked="2" maxchecked="4" required> Orange
      </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Apple" name="docVlCb"> Apple
      </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Pineapple" name="docVlCb"> Pineapple
      </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Mongo" name="docVlCb"> Mongo
      </label>
      <label class="am-checkbox-inline">
        <input type="checkbox" value="Banana" name="docVlCb"> Banana
      </label>
    </div>

    <div class="am-form-group">
      <label>Gender: </label>
      <label class="am-radio-inline">
        <input type="radio"  value="" name="docVlGender" required> Male
      </label>
      <label class="am-radio-inline">
        <input type="radio" name="docVlGender"> Female
      </label>
    </div>

    <div class="am-form-group">
      <label for="doc-select-1">Drowdown</label>
      <select id="doc-select-1" required>
        <option value="">-=Please select one=-</option>
        <option value="option1">Option 1...</option>
        <option value="option2">Option 2.....</option>
        <option value="option3">Option 3........</option>
      </select>
      <span class="am-form-caret"></span>
    </div>

    <div class="am-form-group">
      <label for="doc-select-2">Checkbox</label>
      <select multiple class="" id="doc-select-2" minchecked="2" maxchecked="4">
        <option>1</option>
        <option>2</option>
        <option>3</option>
        <option>4</option>
        <option>5</option>
      </select>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-ta-2">Comment: </label>
      <textarea id="doc-vld-ta-2" minlength="10" maxlength="100"></textarea>
    </div>

    <button class="am-btn am-btn-secondary" type="submit">Submit</button>
  </fieldset>
</form>
$(function() {
  $('#doc-vld-msg').validator({
    onValid: function(validity) {
      $(validity.field).closest('.am-form-group').find('.am-alert').hide();
    },

    onInValid: function(validity) {
      var $field = $(validity.field);
      var $group = $field.closest('.am-form-group');
      var $alert = $group.find('.am-alert');
      // Use customized prompts or default prompts.
      var msg = $field.data('validationMessage') || this.getValidationMessage(validity);

      if (!$alert.length) {
        $alert = $('<div class="am-alert am-alert-danger"></div>').hide().
          appendTo($group);
      }

      $alert.html(msg).show();
    }
  });
});

Tooltip

Define Tooltip
<form action="" class="am-form" id="form-with-tooltip">
  <fieldset>
    <legend>Define Tooltip</legend>
    <div class="am-form-group">
      <label for="doc-vld-name-2-0">Username: </label>
      <input type="text" id="doc-vld-name-2-0" minlength="3"
             placeholder="At least 3 characters" required/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-pwd-1-0">Password: </label>
      <input type="password" id="doc-vld-pwd-1-0" placeholder="Input 6 digits as password" pattern="^\d{6}$" required data-foolish-msg="Give me your password of IQ card!"/>
    </div>

    <button class="am-btn am-btn-secondary" type="submit">Submit</button>
  </fieldset>
</form>

<style>
  #vld-tooltip {
    position: absolute;
    z-index: 1000;
    padding: 5px 10px;
    background: #F37B1D;
    min-width: 150px;
    color: #fff;
    transition: all 0.15s;
    box-shadow: 0 0 5px rgba(0,0,0,.15);
    display: none;
  }

  #vld-tooltip:before {
    position: absolute;
    top: -8px;
    left: 50%;
    width: 0;
    height: 0;
    margin-left: -8px;
    content: "";
    border-width: 0 8px 8px;
    border-color: transparent transparent #F37B1D;
    border-style: none inset solid;
  }
</style>
$(function() {
  var $form = $('#form-with-tooltip');
  var $tooltip = $('<div id="vld-tooltip">Prompts</div>');
  $tooltip.appendTo(document.body);

  $form.validator();

  var validator = $form.data('amui.validator');

  $form.on('focusin focusout', '.am-form-error input', function(e) {
    if (e.type === 'focusin') {
      var $this = $(this);
      var offset = $this.offset();
      var msg = $this.data('foolishMsg') || validator.getValidationMessage($this.data('validity'));

      $tooltip.text(msg).show().css({
        left: offset.left + 10,
        top: offset.top + $(this).outerHeight() + 10
      });
    } else {
      $tooltip.hide();
    }
  });
});

Equivalent Validation

Use data-equal-to to specify the field that need to be validated.

Password Validation
<form action="" class="am-form" data-am-validator>
  <fieldset>
    <legend>Password Validation</legend>
    <div class="am-form-group">
      <label for="doc-vld-name-2">Username:</label>
      <input type="text" id="doc-vld-name-2" minlength="3"
             placeholder="At least 3 characters" required/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-pwd-1">Password: </label>
      <input type="password" id="doc-vld-pwd-1" placeholder="Input 6-digit password" pattern="^\d{6}$" required/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-pwd-2">Confirm Password:</label>
      <input type="password" id="doc-vld-pwd-2" placeholder="Please input the same password as above" data-equal-to="#doc-vld-pwd-1" required/>
    </div>

    <button class="am-btn am-btn-secondary" type="submit">Submit</button>
  </fieldset>
</form>

Customized Validation

There are some requirement that build-in validations can't help with. Therefore, we allow users to customize validation using validate option.

$('#your-form').validator({
  validate: function(validity) {
    // Your validation
  }

The parameter validity is an object like H5 ValidityState attribute. Normally we will only use:

  • validity.field - DOM Object. The field that is being validated. Can be transfer to jQuery object through $(validity.field);
  • validity.valid - Boolean. Whether this field pass the validation. Set it to true if pass. Otherwise, set it to false.

Use following attributes to discribe the detail of validation error:

{
  customError: false,
  patternMismatch: false,
  rangeOverflow: false, // higher than maximum
  rangeUnderflow: false, // lower than  minimum
  stepMismatch: false,
  tooLong: false,
  // value is not in the correct syntax
  typeMismatch: false,
  // Returns true if the element has no value but is a required field
  valueMissing: false
}

Three validation attribute extended by plugin and their corresponding error name are:

  • minlength -> tooShort
  • minchecked -> checkedUnderflow
  • maxchecked -> checkedOverflow

The HTML5 validator use these error details to generate prompts. 插件中暂未使用到这些属性,如果实在不想写,可以略过, The plug in also use these details to generate prompts since v2.3.

Attention

  • Use validity.valid to return whether validation is passed;
  • If this is a remote validation, a Deferred Object must be returned, and validity must be returned by callback function.
return $.ajax({
    url: '...',
    // cache: false. Disable cache in real application.
    dataType: 'json'
  }).then(function(data) {
    // Ajax request success. Set validity.valid = true or false accordingly.

    // return validity
    return validity;
  }, function() {
    // Ajax request fail. Set validity.valid = true or false and return validity.
    return validity;
  });
Customized validation
<form action="" class="am-form" id="doc-vld-ajax">
  <fieldset>
    <legend>Customized validation</legend>
    <div class="am-form-group">
      <label for="doc-vld-ajax-count">Ajax Server-side Validation: </label>
      <input type="text" class="js-ajax-validate" id="doc-vld-ajax-count"
             placeholder="Enter 10" data-validate-async/>
    </div>

    <div class="am-form-group">
      <label for="doc-vld-sync">Client-side Validation: </label>
      <input type="text" class="js-sync-validate" id="doc-vld-sync"
             placeholder="Enter 10"/>
    </div>

    <button class="am-btn am-btn-secondary" type="submit">Submit</button>
  </fieldset>
</form>
$(function() {
  $('#doc-vld-ajax').validator({
    validate: function(validity) {
      var v = $(validity.field).val();

      var comparer = function(v1, v2) {
        if (v1 != v2) {
          validity.valid = false;
        }

        // These attributes are currently not used, so you may dismiss them.
        if (v2 < 10) {
          validity.rangeUnderflow = true;
        } else if(v2 > 10) {
          validity.rangeOverflow = true;
        }
      };

      // Ajax Validation
      if ($(validity.field).is('.js-ajax-validate')) {
        // Return Deferred object
        return $.ajax({
          url: 'https://amazeui.github.io/media/i/demos/validate.json',
          // cache: false    Disable cache in real application. 
          dataType: 'json'
        }).then(function(data) {
          comparer(data.count, v);
          return validity;
        }, function() {
          return validity;
        });
      }

      // Local valication. No return.
      if ($(validity.field).is('.js-sync-validate')) {
        comparer(10, v);
      }
    }
  });
})

Usage

Using Data API

Add data-am-validator attribute to form.

Using JS

$(function() {
  $('#your-form').validator(options);
});

Options

{
  // Whether use H5 validation.
  H5validation: false,

  // Native H5 input types. Don't need to add paterns for them.
  H5inputType: ['email', 'url', 'number'],

  // Use regular expression as patterns
  // key1: /^...$/. Fields include `js-pattern-key1` will be validated with this regular expression
  patterns: {},

  // Prefix of rule classes
  patternClassPrefix: 'js-pattern-',

  activeClass: 'am-active',

  // The class added to field when it doesn't pass the validation
  inValidClass: 'am-field-error',

  // The class added to field when it pass the validation
  validClass: 'am-field-valid',

  // Validate on submit
  validateOnSubmit: true,

  // The field need to be validated on submit
  // Elements to validate with allValid (only validating visible elements)
  // :input: selects all input, textarea, select and button elements.
  allFields: ':input:visible:not(:button, :disabled, .am-novalidate)',

  // The event that call validate() method
  customEvents: 'validate',

  // The following events in following fields will call validation
  keyboardFields: ':input:not(:button, :disabled,.am-novalidate)',
  keyboardEvents: 'focusout, change', // keyup, focusin

  // Validate when keyup fired on the element marked as `.am-active`( invalid validation will be given this class) 
  activeKeyup: false,

  // Validate when keyup fired on textarea[maxlength] element
  textareaMaxlenthKeyup: true,

  // Click on following field will cause validation
  pointerFields: 'input[type="range"]:not(:disabled, .am-novalidate), ' +
  'input[type="radio"]:not(:disabled, .am-novalidate), ' +
  'input[type="checkbox"]:not(:disabled, .am-novalidate), ' +
  'select:not(:disabled, .am-novalidate), ' +
  'option:not(:disabled, .am-novalidate)',
  pointerEvents: 'click',

  // The valid callback function
  onValid: function(validity) {
  },

  // The invalid callback function
  onInValid: function(validity) {
  },

  // This function is called when a field pass the validation. Prompts can be shown in this funciton.
  markValid: function(validity) {
    // this is Validator instance
    var options = this.options;
    var $field  = $(validity.field);
    var $parent = $field.closest('.am-form-group');
    $field.addClass(options.validClass).
      removeClass(options.inValidClass);

    $parent.addClass('am-form-success').removeClass('am-form-error');

    options.onValid.call(this, validity);
  },

  // This function is called when a field fail the validation. Prompts can be shown in this funciton.
  markInValid: function(validity) {
    var options = this.options;
    var $field  = $(validity.field);
    var $parent = $field.closest('.am-form-group');
    $field.addClass(options.inValidClass + ' ' + options.activeClass).
      removeClass(options.validClass);

    $parent.addClass('am-form-error').removeClass('am-form-success');

    options.onInValid.call(this, validity);
  },

  // Customized validation
  validate: function(validity) {
    // return validity;
  },

  // Customized submit
  //   - If there is no defination and `validateOnSubmit` is `true`, the whole form will be validated when submission.
  //   - If submission is defined here, `validateOnSubmit` will be invalid
  //        function(e) {
  //          // Use this.isFormValid() to get the form validation status
  //          // Attention: If the customized validation is an async programe, this.isFormValid() will return a Promise instead of a boolean. 
  //          // Do something...
  //        }
  submit: null
}

Async Validation

When the validation is an async program, isFormValid() returns a Promise, which can use jQuery.when() to handle.

$('#xx').validator({
  submit: function() {
    var formValidity = this.isFormValid();

    $.when(formValidity).then(function() {
      // Success callback
    }, function() {
      // Error callback
    });
  }
});

Extended Regular Expression

The following operations are done before DOM get ready:

(function($) {
  if ($.AMUI && $.AMUI.validator) {
    // Add multiple RegExps
    $.AMUI.validator.patterns = $.extend($.AMUI.validator.patterns, {
      colorHex: /^(#([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))?$/
    });
    // Add single RegExp
    $.AMUI.validator.patterns.yourpattern = /^your$/;
  }
})(window.jQuery);
<form action="" class="am-form" data-am-validator>
  <div class="am-form-group">
    <label for="">Input a color</label>
    <input type="text" class="js-pattern-colorHex" placeholder="Must be #xxx or #xxxxxx"/>
  </div>
  <div class="am-form-group">
    <label for="">your pattern</label>
    <input type="text" class="js-pattern-yourpattern" placeholder="Required. Must be your" required/>
  </div>
  <div>
    <button class="am-btn am-btn-secondary">Submit</button>
  </div>
</form>

Issue Test

#528

Issue 528
<form action="" class="am-form" data-am-validator>
  <fieldset>
    <legend>Issue 528</legend>
    <div class="am-form-group">
      <label for="doc-vld-528">Phone:</label>
      <input type="text" id="doc-vld-528" class="js-pattern-mobile"
             placeholder="Enter phone number" required/>
    </div>
    <button class="am-btn am-btn-secondary" type="submit">Submit</button>
  </fieldset>
</form>
<script>
  if ($.AMUI && $.AMUI.validator) {
    $.AMUI.validator.patterns.mobile = /^\s*1\d{10}\s*$/;
  }
</script>

Reference

Frequently used RegExps:

  • Phone number with zone number:/^(\d{3}-|\d{4}-)(\d{8}|\d{7})$/
  • Chinese characters: /[\u4e00-\u9fa5]/
  • Zip code in China: /^\d{6}$/
  • Mobile phone number in China: /^1((3|5|8){1}\d{1}|70)\d{8}$/

Attention

  • checkbox/radio These two element can't work correctly without name attribute;
  • <input type="number"> returns an empty string "" when input is not an number;
  • Some browser select the first option in dropdo wn by default. Set the first option to be empty by using value="".
<div class="am-form-group">
  <label for="doc-select-1">Dropdown</label>
  <select id="doc-select-1" required>
    <option value="">-=Select one of the options=-</option>
    <option value="option1">Option 1...</option>
    <option value="option2">Option 2.....</option>
    <option value="option3">Option 3........</option>
  </select>
  <span class="am-form-caret"></span>
</div>

Reference

侧栏导航
Amaze UI 微信
在微信上关注我们