Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added validation when submitting an h5Validate enabled form #37

Merged
merged 1 commit into from

3 participants

@joelpurra

Imitates/emulates the native browser form submit validation procedure of Google Chrome, using h5Validate.

  • Prevents the form from submitting if any invalid fields exists.
  • Validates all form fields.
  • Moves focus to the first invalid field.

The first feature needs to be enabled for the other two (optional) features to execute. All three are enabled by default, see documentation and options. Included a bunch of tests; please execute them to confirm the functionality.

@joelpurra

This feature should be in line with this comment on issue#5 from @dilvie.

The plan now is to block submit by default, just as a native browser implementation would probably do, until all inputs validate on the form.

@fabiosantoscode

HTML5 validation is most useful because it stops the user from submitting the form. I consider this a very important feature.

@ericelliott ericelliott merged commit b81e6ff into from
@ericelliott ericelliott referenced this pull request from a commit
@ericelliott Revert "Merge pull request #37 from joelpurra/validate-on-submit"
This reverts commit b81e6ff, reversing
changes made to ecd8559.
d3c8802
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 327 additions and 9 deletions.
  1. +5 −0 index.html
  2. +56 −9 jquery.h5validate.js
  3. +266 −0 test/test.h5validate.js
View
5 index.html
@@ -148,6 +148,11 @@
<p><em>Note: The click event isn't just for the mouse. It will trigger for keyboard and touch screen interactions, too.</em></p>
<code class="block">click: true</code>
</dd>
+ <dt>submit</dt><dd><p>(Event) When enabled, prevents submission of a form that has invalid fields. Performs validation on all fields. If any fields are invalid, it moves focus to the first one. Defaults:</p>
+ <code class="block">submit: true,<br />
+ validateOnSubmit: true,<br />
+ focusFirstInvalidElementOnSubmit: true</code>
+ </dd>
<section>
<h2>Event API</h2>
View
65 jquery.h5validate.js
@@ -80,17 +80,19 @@
patternVar: 'h5-pattern',
stripMarkup: true,
- // Validate on submit?
- // **TODO: This isn't implemented, yet.
+ // Run submit related checks and prevent form submission if any fields are invalid?
submit: true,
- // Callback stubs
- invalidCallback: function () {},
- validCallback: function () {},
+ // Move focus to the first invalid field on submit?
+ focusFirstInvalidElementOnSubmit: true,
// When submitting, validate elements that haven't been validated yet?
validateOnSubmit: true,
+ // Callback stubs
+ invalidCallback: function () {},
+ validCallback: function () {},
+
// Elements to validate with allValid (only validating visible elements)
allValidSelectors: ':input:visible:not(:button):not(:disabled):not(.novalidate)',
@@ -317,7 +319,8 @@
* @returns {object} jQuery object for chaining.
*/
bindDelegation: function (settings) {
- var $this = $(this);
+ var $this = $(this),
+ $forms;
// Attach patterns from the library to elements.
// **TODO: pattern / validation method matching should
// take place inside the validate action.
@@ -327,9 +330,13 @@
$('.' + settings.classPrefix + key).attr('pattern', pattern);
});
- $this.filter('form').attr('novalidate', 'novalidate');
- $this.find('form').attr('novalidate', 'novalidate');
- $this.parents('form').attr('novalidate', 'novalidate');
+ $forms = $this.filter('form')
+ .add($this.find('form'))
+ .add($this.parents('form'));
+
+ $forms
+ .attr('novalidate', 'novalidate')
+ .submit(checkValidityOnSubmitHandler);
return this.each(function () {
var kbEvents = {
@@ -353,6 +360,46 @@
}
},
+ /**
+ * Event handler for the form submit event.
+ * When settings.submit is enabled:
+ * - prevents submission if any invalid fields are found.
+ * - Optionally validates all fields.
+ * - Optionally moves focus to the first invalid field.
+ *
+ * @param {object} evt The jQuery Event object as from the submit event.
+ *
+ * @returns {object} undefined if no validation was done, true if validation passed, false if validation didn't.
+ */
+ checkValidityOnSubmitHandler = function(evt) {
+
+ var $this,
+ settings = getInstance.call(this),
+ allValid;
+
+ if(settings.submit !== true) {
+ return;
+ }
+
+ $this = $(this);
+ allValid = $this.h5Validate('allValid', { revalidate: settings.validateOnSubmit === true });
+
+ if(allValid !== true) {
+ evt.preventDefault();
+
+ if(settings.focusFirstInvalidElementOnSubmit === true){
+ var $invalid = $(settings.allValidSelectors, $this)
+ .filter(function(index){
+ return $(this).h5Validate('isValid', { revalidate: false }) !== true;
+ });
+
+ $invalid.first().focus();
+ }
+ }
+
+ return allValid;
+ },
+
instances = [],
buildSettings = function buildSettings(options) {
View
266 test/test.h5validate.js
@@ -102,6 +102,272 @@
$form.h5Validate('allValid');
});
+ module('Submit handler');
+
+ test('Disabled', 1, function () {
+ var $form = $('<form />', {
+ id: 'submitTest'
+ }),
+ $input1;
+
+ $('<input required id="checked-at-submit-1" value="abc123" />')
+ .appendTo($form);
+
+ $form
+ .appendTo('body');
+
+ $input1 = $('#checked-at-submit-1');
+
+ $form.h5Validate({
+ submit: false
+ });
+
+ $input1.bind('validated', function (event, data) {
+ fail('Validation should not run.');
+ });
+
+ $form.submit(function(evt){
+
+ ok(evt.isDefaultPrevented() !== true, 'Default should not be prevented, despite the invalid fields.');
+
+ // Make sure not to submit in the test code
+ evt.preventDefault();
+ return false;
+ });
+
+ $form.submit();
+
+ $form.remove();
+ });
+
+ test('Enabled, all fields valid', 2, function () {
+ var $form = $('<form />', {
+ id: 'submitTest'
+ }),
+ $input1;
+
+ $('<input required id="checked-at-submit-1" value="abc123" />')
+ .appendTo($form);
+
+ $form
+ .appendTo('body');
+
+ $input1 = $('#checked-at-submit-1');
+
+ $form.h5Validate();
+
+ $input1.bind('validated', function (event, data) {
+ ok(data, 'Validation triggered on submit. #' + data.element.id);
+ });
+
+ $form.submit(function(evt) {
+
+ ok(!evt.isDefaultPrevented(), 'Default should not be prevented, all fields are valid.');
+
+ // Make sure not to submit in the test code
+ evt.preventDefault();
+ return false;
+ });
+
+ $form.submit();
+
+ $form.remove();
+ });
+
+ test('Enabled, some fields invalid', 2, function () {
+ var $form = $('<form />', {
+ id: 'submitTest'
+ }),
+ $input1;
+
+ $('<input required id="checked-at-submit-1" />')
+ .appendTo($form);
+
+ $form
+ .appendTo('body');
+
+ $input1 = $('#checked-at-submit-1');
+
+ $form.h5Validate();
+
+ $input1.bind('validated', function (event, data) {
+ ok(data, 'Validation triggered on submit. #' + data.element.id);
+ });
+
+ $form.submit(function(evt) {
+
+ ok(evt.isDefaultPrevented(), 'Default should be prevented, at least one field is invalid.');
+
+ // Make sure not to submit in the test code
+ evt.preventDefault();
+ return false;
+ });
+
+ $form.submit();
+
+ $form.remove();
+ });
+
+ test('Submit time validation disabled', 1, function () {
+ var $form = $('<form />', {
+ id: 'submitTest'
+ }),
+ $input1;
+
+ $('<input required id="checked-at-submit-1" value="abc123" />')
+ .appendTo($form);
+
+ $form
+ .appendTo('body');
+
+ $input1 = $('#checked-at-submit-1');
+
+ $form.h5Validate({
+ validateOnSubmit: false
+ });
+
+ $input1.bind('validated', function (event, data) {
+ ok(false, 'Validation should not run. #' + data.element.id);
+ });
+
+ $form.submit(function(evt) {
+
+ equal(evt.isDefaultPrevented(), true, 'Form submission should be prevented since validation has not been performed.');
+
+ // Make sure not to submit in the test code
+ evt.preventDefault();
+ return false;
+ });
+
+ $form.submit();
+
+ $form.remove();
+ });
+
+ test('Submit time validation disabled', 2, function () {
+ var $form = $('<form />', {
+ id: 'submitTest'
+ }),
+ $input1,
+ validationShouldRun = false;
+
+ $('<input required id="checked-at-submit-1" value="abc123" />')
+ .appendTo($form);
+
+ $form
+ .appendTo('body');
+
+ $input1 = $('#checked-at-submit-1');
+
+ $form.h5Validate({
+ validateOnSubmit: false
+ });
+
+ $input1.bind('validated', function (event, data) {
+ if(validationShouldRun) {
+ ok(true, 'Validation should run when called manually. #' + data.element.id);
+ } else {
+ ok(false, 'Validation should not run on submit. #' + data.element.id);
+ }
+ });
+
+ $form.submit(function(evt) {
+
+ equal(evt.isDefaultPrevented(), false, 'Form submission should not be prevented since validation has been performed manually.');
+
+ // Make sure not to submit in the test code
+ evt.preventDefault();
+ return false;
+ });
+
+ validationShouldRun = true;
+ $form.h5Validate('allValid');
+
+ validationShouldRun = false;
+ $form.submit();
+
+ $form.remove();
+ });
+
+ test('Focus invalid enabled', 2, function () {
+ var $form = $('<form />', {
+ id: 'submitTest'
+ }),
+ $input1,
+ $input2,
+ $input3,
+ $focused;
+
+ $('<input required id="checked-at-submit-1" value="abc123" />')
+ .appendTo($form);
+
+ $('<input required id="checked-at-submit-2" />')
+ .appendTo($form);
+
+ $('<input required id="checked-at-submit-3" />')
+ .appendTo($form);
+
+ $form
+ .appendTo('body');
+
+ $input3 = $('#checked-at-submit-3');
+
+ // Using default settings
+ $form.h5Validate();
+
+ // Move focus to get a baseline
+ $input3.focus();
+
+ $form.submit();
+
+ $focused = $(':focus');
+ equal($focused.length, 1, 'One element should be focused.');
+ equal($focused.attr('id'), 'checked-at-submit-2', 'The second field is invalid and should be focused.');
+
+ $form.remove();
+ });
+
+ test('Focus invalid disabled', 2, function () {
+ var $form = $('<form />', {
+ id: 'submitTest'
+ }),
+ $input1,
+ $input2,
+ $input3,
+ $focused;
+
+ $('<input required id="checked-at-submit-1" value="abc123" />')
+ .appendTo($form);
+
+ $('<input required id="checked-at-submit-2" />')
+ .appendTo($form);
+
+ $('<input required id="checked-at-submit-3" />')
+ .appendTo($form);
+
+ $form
+ .appendTo('body');
+
+ $input3 = $('#checked-at-submit-3');
+
+ $form.h5Validate({
+ focusFirstInvalidElementOnSubmit: false
+ });
+
+ // Move focus to get a baseline
+ $input3.focus();
+
+ $form.submit();
+
+ $focused = $(':focus');
+ equal($focused.length, 1, 'One element should be focused.');
+ equal($focused.attr('id'), 'checked-at-submit-3', 'The third field should be still focused.');
+
+ $form.remove();
+ });
+
+ module('Issues');
+
test('Issue #29: Disabled fields gum up the works.', function () {
var $form = $('<form>', {
id: 'disabledTest'
Something went wrong with that request. Please try again.