浏览代码

#125: Support dynamic checkbox and radio elements

phuoc 11 年之前
父节点
当前提交
dd50795100
共有 4 个文件被更改,包括 174 次插入56 次删除
  1. 72 22
      demo/dynamic.html
  2. 50 16
      dist/js/bootstrapValidator.js
  3. 2 2
      dist/js/bootstrapValidator.min.js
  4. 50 16
      src/js/bootstrapValidator.js

+ 72 - 22
demo/dynamic.html

@@ -22,31 +22,58 @@
 
                 <form id="defaultForm" method="post" class="form-horizontal" action="target.php">
                     <div class="form-group">
-                        <label class="col-lg-3 control-label">Question</label>
+                        <label class="col-lg-3 control-label">Textbox</label>
                         <div class="col-lg-5">
-                            <input class="form-control" type="text" name="question" />
+                            <input class="form-control" type="text" name="textbox[]" placeholder="Textbox #1" />
                         </div>
-                    </div>
-
-                    <div class="form-group">
-                        <label class="col-lg-3 control-label">Answers</label>
-                        <div class="col-lg-5">
-                            <input class="form-control" type="text" name="answers[]" />
-                        </div>
-                        <div class="col-lg-2">
-                            <button type="button" class="btn btn-default btn-sm addButton">Add</button>
+                        <div class="col-lg-4">
+                            <button type="button" class="btn btn-default btn-sm addButton" data-template="textbox">Add</button>
                         </div>
                     </div>
-                    <div class="form-group hide" id="template">
+                    <div class="form-group hide" id="textboxTemplate">
                         <div class="col-lg-offset-3 col-lg-5">
                             <input class="form-control" type="text" />
                         </div>
-                        <div class="col-lg-2">
+                        <div class="col-lg-4">
                             <button type="button" class="btn btn-default btn-sm removeButton">Remove</button>
                         </div>
                     </div>
 
                     <div class="form-group">
+                        <label class="col-lg-3 control-label">Checkbox</label>
+                        <div class="col-lg-5">
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="checkbox[]" value="Choice #1" /> Choice <button type="button" class="btn btn-default btn-sm addButton" data-template="checkbox">Add</button>
+                                </label>
+                            </div>
+
+                             <div class="checkbox hide template" id="checkboxTemplate">
+                                <label>
+                                    <input type="checkbox" value="1" /> <span class="lbl">Choice</span> <button type="button" class="btn btn-default btn-sm removeButton">Remove</button>
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Radio</label>
+                        <div class="col-lg-5">
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="radio[]" value="Choice #1" /> Choice <button type="button" class="btn btn-default btn-sm addButton" data-template="radio">Add</button>
+                                </label>
+                            </div>
+
+                             <div class="radio hide" id="radioTemplate">
+                                <label>
+                                    <input type="radio" value="1" /> <span class="lbl">Choice</span> <button type="button" class="btn btn-default btn-sm removeButton">Remove</button>
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
                         <div class="col-lg-offset-3 col-lg-3">
                             <button type="submit" class="btn btn-primary">Submit</button>
                         </div>
@@ -60,15 +87,31 @@
 
 <script type="text/javascript">
     $(document).ready(function() {
-        // Add button click handler
         $('.addButton').on('click', function() {
-            var $row = $('#template').clone().removeAttr('id').insertBefore($('#template')).removeClass('hide');
+            var index = $(this).data('index');
+            if (!index) {
+                index = 1;
+                $(this).data('index', 1);
+            }
+            index++;
+            $(this).data('index', index);
+
+            var template     = $(this).attr('data-template'),
+                $templateEle = $('#' + template + 'Template'),
+                $row         = $templateEle.clone().removeAttr('id').insertBefore($templateEle).removeClass('hide'),
+                $el          = $row.find('input').eq(0).attr('name', template + '[]');
+            $('#defaultForm').bootstrapValidator('addFieldElement', $el);
 
-            var $answer = $row.find('input').eq(0).attr('name', 'answers[]');
-            $('#defaultForm').bootstrapValidator('addFieldElement', $answer);
+            // Set random value for checkbox and textbox
+            if ('checkbox' == $el.attr('type') || 'radio' == $el.attr('type')) {
+                $el.val('Choice #' + index)
+                   .parent().find('span.lbl').html('Choice #' + index);
+            } else {
+                $el.attr('placeholder', 'Textbox #' + index);
+            }
 
             $row.on('click', '.removeButton', function(e) {
-                $('#defaultForm').bootstrapValidator('removeFieldElement', $answer);
+                $('#defaultForm').bootstrapValidator('removeFieldElement', $el);
                 $row.remove();
             });
         });
@@ -81,17 +124,24 @@
                 validating: 'glyphicon glyphicon-refresh'
             },
             fields: {
-                question: {
+                'textbox[]': {
+                    validators: {
+                        notEmpty: {
+                            message: 'The textbox field is required'
+                        }
+                    }
+                },
+                'checkbox[]': {
                     validators: {
                         notEmpty: {
-                            message: 'The gender is required'
+                            message: 'The checkbox field is required'
                         }
                     }
                 },
-                'answers[]': {
+                'radio[]': {
                     validators: {
                         notEmpty: {
-                            message: 'The answer is required'
+                            message: 'The radio field is required'
                         }
                     }
                 }

+ 50 - 16
dist/js/bootstrapValidator.js

@@ -33,6 +33,7 @@
         // The flag to indicate that the form is ready to submit when a remote/callback validator returns
         this._submitIfValid = null;
 
+        // Field elements
         this._cacheFields = {};
 
         this._init();
@@ -254,20 +255,20 @@
         },
 
         _initFieldElement: function($field) {
-            var that     = this,
-                field    = $field.attr('name') || $field.attr('data-bv-field'),
-                fields   = this.getFieldElements(field),
-                index    = fields.index($field),
-                type     = $field.attr('type'),
+            var that      = this,
+                field     = $field.attr('name') || $field.attr('data-bv-field'),
+                fields    = this.getFieldElements(field),
+                index     = fields.index($field),
+                type      = $field.attr('type'),
                 total     = fields.length,
                 updateAll = (total == 1) || ('radio' == type) || ('checkbox' == type),
-                $parent  = $field.parents('.form-group'),
+                $parent   = $field.parents('.form-group'),
                 // Allow user to indicate where the error messages are shown
-                $message = this.options.fields[field].container ? $parent.find(this.options.fields[field].container) : this._getMessageContainer($field);
+                $message  = this.options.fields[field].container ? $parent.find(this.options.fields[field].container) : this._getMessageContainer($field);
 
             // Remove all error messages and feedback icons
-            //$message.find('.help-block[data-bv-validator]').remove();
-            //$parent.find('i[data-bv-field]').remove();
+            $message.find('.help-block[data-bv-validator]').remove();
+            $parent.find('i[data-bv-field]').remove();
 
             // Set the attribute to indicate the fields which are defined by selector
             if (!$field.attr('data-bv-field')) {
@@ -276,7 +277,7 @@
 
             // Whenever the user change the field value, mark it as not validated yet
             var event = ('radio' == type || 'checkbox' == type || 'file' == type || 'SELECT' == $field.get(0).tagName) ? 'change' : this._changeEvent;
-            $field.on(event + '.update.bv', function() {
+            $field.off(event + '.update.bv').on(event + '.update.bv', function() {
                 // Reset the flag
                 that._submitIfValid = false;
                 that.updateElementStatus($(this), that.STATUS_NOT_VALIDATED);
@@ -303,7 +304,7 @@
                 && this.options.feedbackIcons.validating && this.options.feedbackIcons.invalid && this.options.feedbackIcons.valid
                 && (!updateAll || index == total - 1))
             {
-                $parent.addClass('has-feedback');
+                $parent.removeClass('has-success').removeClass('has-error').addClass('has-feedback');
                 var $icon = $('<i/>').css('display', 'none').addClass('form-control-feedback').attr('data-bv-field', field).insertAfter($field);
                 // The feedback icon does not render correctly if there is no label
                 // https://github.com/twbs/bootstrap/issues/12873
@@ -728,16 +729,49 @@
 
         // Useful APIs which aren't used internally
 
+        /**
+         * Add new field element
+         *
+         * @param {jQuery} $field The field element
+         * @param {Object} options The field options
+         * @returns {BootstrapValidator}
+         */
         addFieldElement: function($field, options) {
-            var field = $field.attr('name') || $field.attr('data-bv-field');
-            this._cacheFields[field].push($field);
-            this._initFieldElement($field);
+            var field      = $field.attr('name') || $field.attr('data-bv-field'),
+                type       = $field.attr('type'),
+                isNewField = !this._cacheFields[field];
+
+            // Update cache
+            if (!isNewField && this._cacheFields[field].index($field) == -1) {
+                this._cacheFields[field] = this._cacheFields[field].add($field);
+            }
+
+            if ('checkbox' == type || 'radio' == type || isNewField) {
+                this._initField(field);
+            } else {
+                this._initFieldElement($field);
+            }
+
             return this;
         },
 
+        /**
+         * Remove given field element
+         *
+         * @param {jQuery} $field The field element
+         * @returns {BootstrapValidator}
+         */
         removeFieldElement: function($field) {
-            var field = $field.attr('name') || $field.attr('data-bv-field');
-            delete this._cacheFields[field];
+            var field = $field.attr('name') || $field.attr('data-bv-field'),
+                type  = $field.attr('type'),
+                index = this._cacheFields[field].index($field);
+
+            (index == -1) ? (delete this._cacheFields[field]) : this._cacheFields[field].splice(index, 1);
+
+            if ('checkbox' == type || 'radio' == type) {
+                this._initField(field);
+            }
+
             return this;
         },
 

文件差异内容过多而无法显示
+ 2 - 2
dist/js/bootstrapValidator.min.js


+ 50 - 16
src/js/bootstrapValidator.js

@@ -32,6 +32,7 @@
         // The flag to indicate that the form is ready to submit when a remote/callback validator returns
         this._submitIfValid = null;
 
+        // Field elements
         this._cacheFields = {};
 
         this._init();
@@ -253,20 +254,20 @@
         },
 
         _initFieldElement: function($field) {
-            var that     = this,
-                field    = $field.attr('name') || $field.attr('data-bv-field'),
-                fields   = this.getFieldElements(field),
-                index    = fields.index($field),
-                type     = $field.attr('type'),
+            var that      = this,
+                field     = $field.attr('name') || $field.attr('data-bv-field'),
+                fields    = this.getFieldElements(field),
+                index     = fields.index($field),
+                type      = $field.attr('type'),
                 total     = fields.length,
                 updateAll = (total == 1) || ('radio' == type) || ('checkbox' == type),
-                $parent  = $field.parents('.form-group'),
+                $parent   = $field.parents('.form-group'),
                 // Allow user to indicate where the error messages are shown
-                $message = this.options.fields[field].container ? $parent.find(this.options.fields[field].container) : this._getMessageContainer($field);
+                $message  = this.options.fields[field].container ? $parent.find(this.options.fields[field].container) : this._getMessageContainer($field);
 
             // Remove all error messages and feedback icons
-            //$message.find('.help-block[data-bv-validator]').remove();
-            //$parent.find('i[data-bv-field]').remove();
+            $message.find('.help-block[data-bv-validator]').remove();
+            $parent.find('i[data-bv-field]').remove();
 
             // Set the attribute to indicate the fields which are defined by selector
             if (!$field.attr('data-bv-field')) {
@@ -275,7 +276,7 @@
 
             // Whenever the user change the field value, mark it as not validated yet
             var event = ('radio' == type || 'checkbox' == type || 'file' == type || 'SELECT' == $field.get(0).tagName) ? 'change' : this._changeEvent;
-            $field.on(event + '.update.bv', function() {
+            $field.off(event + '.update.bv').on(event + '.update.bv', function() {
                 // Reset the flag
                 that._submitIfValid = false;
                 that.updateElementStatus($(this), that.STATUS_NOT_VALIDATED);
@@ -302,7 +303,7 @@
                 && this.options.feedbackIcons.validating && this.options.feedbackIcons.invalid && this.options.feedbackIcons.valid
                 && (!updateAll || index == total - 1))
             {
-                $parent.addClass('has-feedback');
+                $parent.removeClass('has-success').removeClass('has-error').addClass('has-feedback');
                 var $icon = $('<i/>').css('display', 'none').addClass('form-control-feedback').attr('data-bv-field', field).insertAfter($field);
                 // The feedback icon does not render correctly if there is no label
                 // https://github.com/twbs/bootstrap/issues/12873
@@ -727,16 +728,49 @@
 
         // Useful APIs which aren't used internally
 
+        /**
+         * Add new field element
+         *
+         * @param {jQuery} $field The field element
+         * @param {Object} options The field options
+         * @returns {BootstrapValidator}
+         */
         addFieldElement: function($field, options) {
-            var field = $field.attr('name') || $field.attr('data-bv-field');
-            this._cacheFields[field].push($field);
-            this._initFieldElement($field);
+            var field      = $field.attr('name') || $field.attr('data-bv-field'),
+                type       = $field.attr('type'),
+                isNewField = !this._cacheFields[field];
+
+            // Update cache
+            if (!isNewField && this._cacheFields[field].index($field) == -1) {
+                this._cacheFields[field] = this._cacheFields[field].add($field);
+            }
+
+            if ('checkbox' == type || 'radio' == type || isNewField) {
+                this._initField(field);
+            } else {
+                this._initFieldElement($field);
+            }
+
             return this;
         },
 
+        /**
+         * Remove given field element
+         *
+         * @param {jQuery} $field The field element
+         * @returns {BootstrapValidator}
+         */
         removeFieldElement: function($field) {
-            var field = $field.attr('name') || $field.attr('data-bv-field');
-            delete this._cacheFields[field];
+            var field = $field.attr('name') || $field.attr('data-bv-field'),
+                type  = $field.attr('type'),
+                index = this._cacheFields[field].index($field);
+
+            (index == -1) ? (delete this._cacheFields[field]) : this._cacheFields[field].splice(index, 1);
+
+            if ('checkbox' == type || 'radio' == type) {
+                this._initField(field);
+            }
+
             return this;
         },