Browse Source

#44: Implement custom submitHandler

nghuuphuoc 11 years ago
parent
commit
56effb25fd

+ 68 - 33
dist/js/bootstrapValidator.js

@@ -14,10 +14,13 @@
         this.options = $.extend({}, BootstrapValidator.DEFAULT_OPTIONS, options);
 
         // Array of deferred
-        this._dfds          = {};
+        this._dfds   = {};
 
-        // Invalid fields
-        this._invalidFields = {};
+        // First invalid field
+        this._firstInvalidField = null;
+
+        // Validating results
+        this._results = {};
 
         this._init();
     };
@@ -30,6 +33,15 @@
         // Default invalid message
         message: 'This value is not valid',
 
+        // The custom submit handler
+        // It will prevent the form from the default submission
+        //
+        //  submitHandler: function(validator, form) {
+        //      - validator is the BootstrapValidator instance
+        //      - form is the jQuery object present the current form
+        //  }
+        submitHandler: null,
+
         // Live validating option
         // Can be one of 3 values:
         // - enabled: The plugin validates fields as soon as they are changed
@@ -57,7 +69,8 @@
                 // Disable client side validation in HTML 5
                 .attr('novalidate', 'novalidate')
                 .addClass(this.options.elementClass)
-                .on('submit', function(e) {
+                // Disable the default submission first
+                .on('submit.bootstrapValidator', function(e) {
                     e.preventDefault();
                     that.validate();
                 });
@@ -79,7 +92,8 @@
                 return;
             }
 
-            this._dfds[field] = {};
+            this._dfds[field]    = {};
+            this._results[field] = {};
 
             var fields = this.$form.find('[name="' + field + '"]');
             if (fields.length == 0) {
@@ -121,6 +135,12 @@
 
             if (size && offset) {
                 for (var validatorName in this.options.fields[field].validators) {
+                    if (!$.fn.bootstrapValidator.validators[validatorName]) {
+                        delete this.options.fields[field].validators[validatorName];
+                        continue;
+                    }
+
+                    this._results[field][validatorName] = null;
                     $('<small/>')
                         .css('display', 'none')
                         .attr('data-bs-validator', validatorName)
@@ -157,6 +177,33 @@
             }
         },
 
+        /**
+         * Called when all validations are completed
+         */
+        _submit: function() {
+            if (!this.isValid()) {
+                if ('submitted' == this.options.live) {
+                    this.options.live = 'enabled';
+                    this._setLiveValidating();
+                }
+
+                // Focus to the first invalid field
+                if (this._firstInvalidField) {
+                    this.getFieldElements(this._firstInvalidField).focus();
+                }
+
+                return;
+            }
+
+            // Call the custom submission if enabled
+            if (this.options.submitHandler && 'function' == typeof this.options.submitHandler) {
+                this.options.submitHandler.call(this, this, this.$form);
+            } else {
+                // Submit form
+                //this.$form.off('submit.bootstrapValidator').submit();
+            }
+        },
+
         // --- Public methods ---
 
         /**
@@ -174,8 +221,6 @@
          * Validate the form
          */
         validate: function() {
-            // Reset invalid fields
-            this._invalidFields = {};
             if (!this.options.fields) {
                 return;
             }
@@ -183,12 +228,7 @@
                 this.validateField(field);
             }
 
-            if (!this.isValid()) {
-                if ('submitted' == this.options.live) {
-                    this.options.live = 'enabled';
-                    this._setLiveValidating();
-                }
-            }
+            this._submit();
         },
 
         /**
@@ -204,16 +244,6 @@
                 validatorName,
                 validateResult;
             for (validatorName in validators) {
-//                if (this._invalidFields[field]) {
-//                    break;
-//                }
-
-                // Continue if the validator with given name doesn't exist
-                if (!$.fn.bootstrapValidator.validators[validatorName]) {
-                    delete this.options.fields[field].validators[validatorName];
-                    continue;
-                }
-
                 if (this._dfds[field][validatorName]) {
                     this._dfds[field][validatorName].reject();
                 }
@@ -221,14 +251,21 @@
                 validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]);
                 if ('object' == typeof validateResult) {
                     this._dfds[field][validatorName] = validateResult;
+                    validateResult.done(function(isValid, v) {
+                        // v is validator name
+                        delete that._dfds[field][v];
+                        /*
+                        if (isValid) {
+                            that._submit();
+                        }*/
+                    });
                 }
 
                 $.when(validateResult).then(function(isValid) {
-                    delete that._dfds[field][validatorName];
+                    that._results[field][validatorName] = isValid;
                     if (isValid) {
                         that.removeError($field, validatorName);
                     } else {
-                        that._invalidFields[field] = true;
                         that.showError($field, validatorName);
                     }
                 });
@@ -242,12 +279,10 @@
          */
         isValid: function() {
             var field, validatorName;
-            for (field in this._invalidFields) {
-                return false;
-            }
-            for (field in this._dfds) {
-                for (validatorName in this._dfds[field]) {
-                    if ('pending' == this._dfds[field][validatorName].state()) {
+            for (field in this._results) {
+                for (validatorName in this._results[field]) {
+                    if (!this._results[field][validatorName]) {
+                        this._firstInvalidField = field;
                         return false;
                     }
                 }
@@ -354,7 +389,7 @@
             var value = $field.val();
             if (options.callback && 'function' == typeof options.callback) {
                 var dfd = new $.Deferred();
-                dfd.resolve(options.callback.call(this, value, validator));
+                dfd.resolve(options.callback.call(this, value, validator), 'callback');
                 return dfd;
             }
             return true;
@@ -657,7 +692,7 @@
                 data: data
             });
             xhr.then(function(response) {
-                dfd.resolve(response.valid === true || response.valid === 'true');
+                dfd.resolve(response.valid === true || response.valid === 'true', 'remote');
             });
 
             dfd.fail(function() {

File diff suppressed because it is too large
+ 1 - 1
dist/js/bootstrapValidator.min.js


+ 66 - 31
src/js/bootstrapValidator.js

@@ -14,10 +14,13 @@
         this.options = $.extend({}, BootstrapValidator.DEFAULT_OPTIONS, options);
 
         // Array of deferred
-        this._dfds          = {};
+        this._dfds   = {};
 
-        // Invalid fields
-        this._invalidFields = {};
+        // First invalid field
+        this._firstInvalidField = null;
+
+        // Validating results
+        this._results = {};
 
         this._init();
     };
@@ -30,6 +33,15 @@
         // Default invalid message
         message: 'This value is not valid',
 
+        // The custom submit handler
+        // It will prevent the form from the default submission
+        //
+        //  submitHandler: function(validator, form) {
+        //      - validator is the BootstrapValidator instance
+        //      - form is the jQuery object present the current form
+        //  }
+        submitHandler: null,
+
         // Live validating option
         // Can be one of 3 values:
         // - enabled: The plugin validates fields as soon as they are changed
@@ -57,7 +69,8 @@
                 // Disable client side validation in HTML 5
                 .attr('novalidate', 'novalidate')
                 .addClass(this.options.elementClass)
-                .on('submit', function(e) {
+                // Disable the default submission first
+                .on('submit.bootstrapValidator', function(e) {
                     e.preventDefault();
                     that.validate();
                 });
@@ -79,7 +92,8 @@
                 return;
             }
 
-            this._dfds[field] = {};
+            this._dfds[field]    = {};
+            this._results[field] = {};
 
             var fields = this.$form.find('[name="' + field + '"]');
             if (fields.length == 0) {
@@ -121,6 +135,12 @@
 
             if (size && offset) {
                 for (var validatorName in this.options.fields[field].validators) {
+                    if (!$.fn.bootstrapValidator.validators[validatorName]) {
+                        delete this.options.fields[field].validators[validatorName];
+                        continue;
+                    }
+
+                    this._results[field][validatorName] = null;
                     $('<small/>')
                         .css('display', 'none')
                         .attr('data-bs-validator', validatorName)
@@ -157,6 +177,33 @@
             }
         },
 
+        /**
+         * Called when all validations are completed
+         */
+        _submit: function() {
+            if (!this.isValid()) {
+                if ('submitted' == this.options.live) {
+                    this.options.live = 'enabled';
+                    this._setLiveValidating();
+                }
+
+                // Focus to the first invalid field
+                if (this._firstInvalidField) {
+                    this.getFieldElements(this._firstInvalidField).focus();
+                }
+
+                return;
+            }
+
+            // Call the custom submission if enabled
+            if (this.options.submitHandler && 'function' == typeof this.options.submitHandler) {
+                this.options.submitHandler.call(this, this, this.$form);
+            } else {
+                // Submit form
+                //this.$form.off('submit.bootstrapValidator').submit();
+            }
+        },
+
         // --- Public methods ---
 
         /**
@@ -174,8 +221,6 @@
          * Validate the form
          */
         validate: function() {
-            // Reset invalid fields
-            this._invalidFields = {};
             if (!this.options.fields) {
                 return;
             }
@@ -183,12 +228,7 @@
                 this.validateField(field);
             }
 
-            if (!this.isValid()) {
-                if ('submitted' == this.options.live) {
-                    this.options.live = 'enabled';
-                    this._setLiveValidating();
-                }
-            }
+            this._submit();
         },
 
         /**
@@ -204,16 +244,6 @@
                 validatorName,
                 validateResult;
             for (validatorName in validators) {
-//                if (this._invalidFields[field]) {
-//                    break;
-//                }
-
-                // Continue if the validator with given name doesn't exist
-                if (!$.fn.bootstrapValidator.validators[validatorName]) {
-                    delete this.options.fields[field].validators[validatorName];
-                    continue;
-                }
-
                 if (this._dfds[field][validatorName]) {
                     this._dfds[field][validatorName].reject();
                 }
@@ -221,14 +251,21 @@
                 validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]);
                 if ('object' == typeof validateResult) {
                     this._dfds[field][validatorName] = validateResult;
+                    validateResult.done(function(isValid, v) {
+                        // v is validator name
+                        delete that._dfds[field][v];
+                        /*
+                        if (isValid) {
+                            that._submit();
+                        }*/
+                    });
                 }
 
                 $.when(validateResult).then(function(isValid) {
-                    delete that._dfds[field][validatorName];
+                    that._results[field][validatorName] = isValid;
                     if (isValid) {
                         that.removeError($field, validatorName);
                     } else {
-                        that._invalidFields[field] = true;
                         that.showError($field, validatorName);
                     }
                 });
@@ -242,12 +279,10 @@
          */
         isValid: function() {
             var field, validatorName;
-            for (field in this._invalidFields) {
-                return false;
-            }
-            for (field in this._dfds) {
-                for (validatorName in this._dfds[field]) {
-                    if ('pending' == this._dfds[field][validatorName].state()) {
+            for (field in this._results) {
+                for (validatorName in this._results[field]) {
+                    if (!this._results[field][validatorName]) {
+                        this._firstInvalidField = field;
                         return false;
                     }
                 }

+ 1 - 1
src/js/validator/callback.js

@@ -18,7 +18,7 @@
             var value = $field.val();
             if (options.callback && 'function' == typeof options.callback) {
                 var dfd = new $.Deferred();
-                dfd.resolve(options.callback.call(this, value, validator));
+                dfd.resolve(options.callback.call(this, value, validator), 'callback');
                 return dfd;
             }
             return true;

+ 1 - 1
src/js/validator/remote.js

@@ -34,7 +34,7 @@
                 data: data
             });
             xhr.then(function(response) {
-                dfd.resolve(response.valid === true || response.valid === 'true');
+                dfd.resolve(response.valid === true || response.valid === 'true', 'remote');
             });
 
             dfd.fail(function() {