Browse Source

Merge pull request #3274 from jewway/fix_#2671

Fix #2671 - Select2-filter + column sort doesn't work
文翼 8 years ago
parent
commit
c4f309eb40

+ 25 - 5
src/extensions/select2-filter/README.md

@@ -1,7 +1,7 @@
 # Table Select2 Filter
 
 Use Plugin: [bootstrap-table-select2-filter](https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/select2-filter) </br>
-Dependence if you use the select2 option: [Select2](https://select2.github.io/) v4.0.0
+Dependence if you use the select2 option: [Select2](https://select2.github.io/) v4.0.0 upper
 
 ## Usage
 
@@ -20,26 +20,46 @@ Dependence if you use the select2 option: [Select2](https://select2.github.io/)
 ### filterValues
 
 * type: Object
-* description: Set default selected value. <br>Example: {columnA.field.:'Column A Selected Value',columnB.field:'Column B Selected Value'}
+* description: Set default selected value. <br>Example: <code>{columnA.field.:'Column A Selected Value',columnB.field:'Column B Selected Value'}</code>
 * default: `undefined`
 
+### filterTemplate
+* type: Object
+* description: customize default filter template. <br>Example: <code> {
+&nbsp;&nbsp;input: function (bootstrapTable, column, isVisible) {
+&nbsp;&nbsp;return `'<input type="text" class="form-control input-sm" data-filter-field="' + column.field + '" style="width: 100%; visibility:' + isVisible + '">'`;
+          }
+</code>
+
 ## Column options
 
 ### filter
 
 * type: Object
 * description: Set filter option to configure the filter. <br>Example: {type:'select', data:["itemA", "itemB", "itemC"]}
-	* type: add an `input` or `select` into the column.
+	* type: default support adding `input` or `select` into the column.
 	* data: need to set when type is `select` , filter data list. (The same as [Select2 Options](http://select2.github.io/examples.html#data))
 * default: `undefined`
+* customize filter: <code>  filter: {
+&nbsp;template: // HTML String or jQuery Object,
+&nbsp;setFilterValue: function ($filter, field, value) { <br>&nbsp;&nbsp;&nbsp;&nbsp;// set template default value.
+&nbsp;}
+            }
+</code>
 
 ## Methods
 
-### setFilterData
+### setSelect2Data
 
 
 * Set column's filter data.
   * Parameters
       * String : column field.
       * Object : filter data list.
-  * Example: <code> $table.bootstrapTable("setFilterData", "columnA.filed", ["itemA", "itemB", "itemC"]);</code>
+  * Example: <code> $table.bootstrapTable("setSelect2Data", "columnA.filed", ["itemA", "itemB", "itemC"]);</code>
+
+
+### setFilterValues
+  * Parameters
+      * Object : column field / default value.
+  * Example: <code> $table.bootstrapTable("setFilterValues",  {columnA.field.:'Column A Selected Value',columnB.field:'Column B Selected Value'});</code>

+ 135 - 106
src/extensions/select2-filter/bootstrap-table-select2-filter.js

@@ -1,9 +1,9 @@
 /**
  * @author: Jewway
- * @version: v1.0.0
+ * @version: v1.1.1
  */
 
-!function ($) {
+! function ($) {
   'use strict';
 
   function getCurrentHeader(that) {
@@ -15,23 +15,26 @@
     return header;
   }
 
-  function getFilterFields(that) {
-    return getCurrentHeader(that).find('[data-filter-field]');
-  }
-
-  function setFilterValues(that) {
-    var $filterElms = getFilterFields(that);
+  function initFilterValues(that) {
     if (!$.isEmptyObject(that.filterColumnsPartial)) {
-      $filterElms.each(function (index, ele) {
-        var $ele = $(ele),
-            field = $ele.attr('data-filter-field'),
-            value = that.filterColumnsPartial[field];
+      var $header = getCurrentHeader(that);
 
-        if ($ele.is("select")) {
-          $ele.val(value).trigger('change');
-        }
-        else {
-          $ele.val(value);
+      $.each(that.columns, function (idx, column) {
+        var value = that.filterColumnsPartial[column.field];
+
+        if (column.filter) {
+          if (column.filter.setFilterValue) {
+            var $filter = $header.find('[data-field=' + column.field + '] .filter');
+            column.filter.setFilterValue($filter, column.field, value);
+          } else {
+            var $ele = $header.find('[data-filter-field=' + column.field + ']');
+            switch (column.filter.type) {
+              case 'input':
+                $ele.val(value);
+              case 'select':
+                $ele.val(value).trigger('change');
+            }
+          }
         }
       });
     }
@@ -39,89 +42,109 @@
 
   function createFilter(that, header) {
     var enableFilter = false,
-        isVisible,
-        html,
-        timeoutId = 0;
+      isVisible,
+      html,
+      timeoutId = 0;
 
     $.each(that.columns, function (i, column) {
       isVisible = 'hidden';
-      html = [];
+      html = null;
 
       if (!column.visible) {
         return;
       }
 
       if (!column.filter) {
-        html.push('<div class="no-filter"></div>');
+        html = $('<div class="no-filter"></div>');
       } else {
         var filterClass = column.filter.class ? ' ' + column.filter.class : '';
-        html.push('<div style="margin: 0px 2px 2px 2px;" class="filter' + filterClass + '">');
+        html = $('<div style="margin: 0px 2px 2px 2px;" class="filter' + filterClass + '">');
 
         if (column.searchable) {
           enableFilter = true;
           isVisible = 'visible'
         }
 
-        switch (column.filter.type.toLowerCase()) {
-          case 'input' :
-            html.push('<input type="text" data-filter-field="' + column.field + '" style="width: 100%; visibility:' + isVisible + '">');
-            break;
-          case 'select':
-            html.push('<select data-filter-field="' + column.field + '" style="width: 100%; visibility:' + isVisible + '"></select>');
-            break;
+        if (column.filter.template) {
+          html.append(column.filter.template(that, column, isVisible));
+        } else {
+          var $filter = $(that.options.filterTemplate[column.filter.type.toLowerCase()](that, column, isVisible));
+
+          switch (column.filter.type) {
+            case 'input':
+              var cpLock = true;
+              $filter.off('compositionstart').on('compositionstart', function (event) {
+                cpLock = false;
+              });
+
+              $filter.off('compositionend').on('compositionend', function (event) {
+                cpLock = true;
+                var $input = $(this);
+                clearTimeout(timeoutId);
+                timeoutId = setTimeout(function () {
+                  that.onColumnSearch(event, column.field, $input.val());
+                }, that.options.searchTimeOut);
+              });
+
+              $filter.off('keyup').on('keyup', function (event) {
+                if (cpLock) {
+                  var $input = $(this);
+                  clearTimeout(timeoutId);
+                  timeoutId = setTimeout(function () {
+                    that.onColumnSearch(event, column.field, $input.val());
+                  }, that.options.searchTimeOut);
+                }
+              });
+
+              $filter.off('mouseup').on('mouseup', function (event) {
+                var $input = $(this),
+                  oldValue = $input.val();
+
+                if (oldValue === "") {
+                  return;
+                }
+
+                setTimeout(function () {
+                  var newValue = $input.val();
+
+                  if (newValue === "") {
+                    clearTimeout(timeoutId);
+                    timeoutId = setTimeout(function () {
+                      that.onColumnSearch(event, column.field, newValue);
+                    }, that.options.searchTimeOut);
+                  }
+                }, 1);
+              });
+              break;
+            case 'select':
+              $filter.on('select2:select', function (event) {
+                that.onColumnSearch(event, column.field, $(this).val());
+              });
+
+              $filter.on("select2:unselecting", function (event) {
+                var $select2 = $(this);
+                event.preventDefault();
+                $select2.val(null).trigger('change');
+                that.searchText = undefined;
+                that.onColumnSearch(event, column.field, $select2.val());
+              });
+              break;
+          }
+
+          html.append($filter);
         }
       }
 
       $.each(header.children().children(), function (i, tr) {
         tr = $(tr);
         if (tr.data('field') === column.field) {
-          tr.find('.fht-cell').append(html.join(''));
+          tr.find('.fht-cell').append(html);
           return false;
         }
       });
     });
 
-    if (enableFilter) {
-      var $inputs = header.find('input'),
-          $selects = header.find('select');
-
-
-      if ($inputs.length > 0) {
-        $inputs.off('keyup').on('keyup', function (event) {
-          clearTimeout(timeoutId);
-          timeoutId = setTimeout(function () {
-            that.onColumnSearch(event);
-          }, that.options.searchTimeOut);
-        });
-
-
-        $inputs.off('mouseup').on('mouseup', function (event) {
-          var $input = $(this),
-              oldValue = $input.val();
-
-          if (oldValue === "") {
-            return;
-          }
-
-          setTimeout(function () {
-            var newValue = $input.val();
-
-            if (newValue === "") {
-              clearTimeout(timeoutId);
-              timeoutId = setTimeout(function () {
-                that.onColumnSearch(event);
-              }, that.options.searchTimeOut);
-            }
-          }, 1);
-        });
-      }
-
-      if ($selects.length > 0) {
-        $selects.on('select2:select', function (event) {
-          that.onColumnSearch(event);
-        });
-      }
-    } else {
+    if (!enableFilter) {
       header.find('.filter').hide();
     }
   }
@@ -134,8 +157,6 @@
         var $selectEle = $header.find('select[data-filter-field="' + column.field + '"]');
 
         if ($selectEle.length > 0 && !$selectEle.data().select2) {
-          column.filter.data.unshift("");
-
           var select2Opts = {
             placeholder: "",
             allowClear: true,
@@ -144,12 +165,6 @@
           };
 
           $selectEle.select2(select2Opts);
-          $selectEle.on("select2:unselecting", function (event) {
-            event.preventDefault();
-            $selectEle.val(null).trigger('change');
-            that.searchText = undefined;
-            that.onColumnSearch(event);
-          });
         }
       }
     });
@@ -157,23 +172,42 @@
 
   $.extend($.fn.bootstrapTable.defaults, {
     filter: false,
-    filterValues: {}
+    filterValues: {},
+    filterTemplate: {
+      input: function (instance, column, isVisible) {
+        return '<input type="text" class="form-control" data-filter-field="' + column.field + '" style="width: 100%; visibility:' + isVisible + '">';
+      },
+      select: function (instance, column, isVisible) {
+        return '<select data-filter-field="' + column.field + '" style="width: 100%; visibility:' + isVisible + '"></select>';
+      }
+    },
+    onColumnSearch: function (field, text) {
+      return false;
+    }
   });
 
   $.extend($.fn.bootstrapTable.COLUMN_DEFAULTS, {
     filter: undefined
   });
 
+  $.extend($.fn.bootstrapTable.Constructor.EVENTS, {
+    'column-search.bs.table': 'onColumnSearch'
+  });
+
   var BootstrapTable = $.fn.bootstrapTable.Constructor,
-      _init = BootstrapTable.prototype.init,
-      _initHeader = BootstrapTable.prototype.initHeader,
-      _initSearch = BootstrapTable.prototype.initSearch;
+    _init = BootstrapTable.prototype.init,
+    _initHeader = BootstrapTable.prototype.initHeader,
+    _initSearch = BootstrapTable.prototype.initSearch;
 
   BootstrapTable.prototype.init = function () {
     //Make sure that the filtercontrol option is set
     if (this.options.filter) {
       var that = this;
 
+      if (that.options.filterTemplate) {
+        that.options.filterTemplate = $.extend({}, $.fn.bootstrapTable.defaults.filterTemplate, that.options.filterTemplate);
+      }
+
       if (!$.isEmptyObject(that.options.filterValues)) {
         that.filterColumnsPartial = that.options.filterValues;
         that.options.filterValues = {};
@@ -197,10 +231,10 @@
         initSelect2(that);
         clearTimeout(timeoutId);
         timeoutId = setTimeout(function () {
-          setFilterValues(that);
+          initFilterValues(that);
         }, that.options.searchTimeOut - 1000);
       }).on('column-switch.bs.table', function (field, checked) {
-        setFilterValues(that);
+        initFilterValues(that);
       });
     }
 
@@ -215,23 +249,20 @@
   };
 
   BootstrapTable.prototype.initSearch = function () {
-    _initSearch.apply(this, Array.prototype.slice.apply(arguments));
-
     var that = this,
-        filterValues = that.filterColumnsPartial;
+      filterValues = that.filterColumnsPartial;
 
     // Filter for client
     if (that.options.sidePagination === 'client') {
       this.data = $.grep(this.data, function (row, idx) {
         for (var field in filterValues) {
-          var column = that.columns[that.fieldsColumnsIndex[field]],
-              filterValue = filterValues[field].toLowerCase(),
-              rowValue = row[field];
-
+          var column = that.columns[$.fn.bootstrapTable.utils.getFieldIndex(that.columns, field)],
+            filterValue = filterValues[field].toLowerCase(),
+            rowValue = row[field];
+          
           rowValue = $.fn.bootstrapTable.utils.calculateObjectValue(
-              that.header,
-              that.header.formatters[$.inArray(field, that.header.fields)],
-              [rowValue, row, idx], rowValue);
+            that.header,
+            that.header.formatters[$.inArray(field, that.header.fields)], [rowValue, row, idx], rowValue);
 
           if (column.filterStrictSearch) {
             if (!($.inArray(field, that.header.fields) !== -1 &&
@@ -251,12 +282,11 @@
         return true;
       });
     }
-  };
 
-  BootstrapTable.prototype.onColumnSearch = function (event) {
-    var field = $(event.currentTarget).attr('data-filter-field'),
-        value = $.trim($(event.currentTarget).val());
+    _initSearch.apply(this, Array.prototype.slice.apply(arguments));
+  };
 
+  BootstrapTable.prototype.onColumnSearch = function (event, field, value) {
     if ($.isEmptyObject(this.filterColumnsPartial)) {
       this.filterColumnsPartial = {};
     }
@@ -269,14 +299,13 @@
 
     this.options.pageNumber = 1;
     this.onSearch(event);
+    this.trigger('column-search', field, value);
   };
 
-  BootstrapTable.prototype.setFilterData = function (field, data) {
+  BootstrapTable.prototype.setSelect2Data = function (field, data) {
     var that = this,
-        $header = getCurrentHeader(that),
-        $selectEle = $header.find('select[data-filter-field=\"' + field + '\"]');
-
-    data.unshift("");
+      $header = getCurrentHeader(that),
+      $selectEle = $header.find('select[data-filter-field=\"' + field + '\"]');
     $selectEle.empty();
     $selectEle.select2({
       data: data,
@@ -297,7 +326,7 @@
     this.filterColumnsPartial = values;
   };
 
-  $.fn.bootstrapTable.methods.push('setFilterData');
+  $.fn.bootstrapTable.methods.push('setSelect2Data');
   $.fn.bootstrapTable.methods.push('setFilterValues');
 
 }(jQuery);

+ 128 - 0
src/extensions/select2-filter/data.json

@@ -0,0 +1,128 @@
+[
+  {
+    "id": 0,
+    "name": "Item 0",
+    "price": "$0",
+    "amount": 3
+  },
+  {
+    "id": 1,
+    "name": "Item 1",
+    "price": "$1",
+    "amount": 4
+  },
+  {
+    "id": 2,
+    "name": "Item 2",
+    "price": "$2",
+    "amount": 8
+  },
+  {
+    "id": 3,
+    "name": "Item 3",
+    "price": "$3",
+    "amount": 2
+  },
+  {
+    "id": 4,
+    "name": "Item 4",
+    "price": "$4",
+    "amount": 90
+  },
+  {
+    "id": 5,
+    "name": "Item 5",
+    "price": "$5",
+    "amount": 2
+  },
+  {
+    "id": 6,
+    "name": "Item 6",
+    "price": "$6",
+    "amount": 3
+  },
+  {
+    "id": 7,
+    "name": "Item 7",
+    "price": "$7",
+    "amount": 7
+  },
+  {
+    "id": 8,
+    "name": "Item 8",
+    "price": "$8",
+    "amount": 39
+  },
+  {
+    "id": 9,
+    "name": "Item 9",
+    "price": "$9",
+    "amount": 78
+  },
+  {
+    "id": 10,
+    "name": "Item 10",
+    "price": "$10",
+    "amount": 30
+  },
+  {
+    "id": 11,
+    "name": "Item 11",
+    "price": "$11",
+    "amount": 32
+  },
+  {
+    "id": 12,
+    "name": "Item 12",
+    "price": "$12",
+    "amount": 12
+  },
+  {
+    "id": 13,
+    "name": "Item 13",
+    "price": "$13",
+    "amount": 76
+  },
+  {
+    "id": 14,
+    "name": "Item 14",
+    "price": "$14",
+    "amount": 10
+  },
+  {
+    "id": 15,
+    "name": "Item 15",
+    "price": "$15",
+    "amount": 9
+  },
+  {
+    "id": 16,
+    "name": "Item 16",
+    "price": "$16",
+    "amount": 8
+  },
+  {
+    "id": 17,
+    "name": "Item 17",
+    "price": "$17",
+    "amount": 1
+  },
+  {
+    "id": 18,
+    "name": "Item 18",
+    "price": "$18",
+    "amount": 99
+  },
+  {
+    "id": 19,
+    "name": "Item 19",
+    "price": "$19",
+    "amount": 100
+  },
+  {
+    "id": 20,
+    "name": "Item 20",
+    "price": "$20",
+    "amount": 109
+  }
+]

+ 1 - 1
src/extensions/select2-filter/extension.json

@@ -1,6 +1,6 @@
 {
   "name": "Select2 Filter",
-  "version": "1.0.0",
+  "version": "1.1.0",
   "description": "Plugin to add select2 filter on the top of the columns in order to filter the data.",
   "url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/select2-filter",
   "example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/select2-filter.html",

+ 119 - 0
src/extensions/select2-filter/select2-filter.html

@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Select2 Filter</title>
+  <meta charset="utf-8">
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/css/select2.min.css"/>
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css"/>
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.1/bootstrap-table.min.css"/>
+
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/js/select2.min.js"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.1/bootstrap-table.min.js"></script>
+  <script src="bootstrap-table-select2-filter.js"></script>
+  <script>
+    $(function () {
+      function getNumberFilterTemplate(fieldId) {
+        var numberFilterClass = 'numberFilter-' + fieldId,
+                template = function (bootstrapTable, col, isVisible) {
+                  var search = function (event, value) {
+                    bootstrapTable.searchText = undefined;
+                    clearTimeout(bootstrapTable.timeoutId);
+                    bootstrapTable.timeoutId = setTimeout(function () {
+                      bootstrapTable.onColumnSearch(event, fieldId, value);
+                    }, bootstrapTable.options.searchTimeOut);
+                  };
+
+                  var $el = $('<div class="input-group input-group-sm ' + numberFilterClass + '" style="width: 100%; visibility:' + isVisible + '">' +
+                                  '<span class="input-group-addon">&gt;</span>' +
+                                  '<input type="number" class="form-control">' +
+                                  '</div>'),
+                          $input = $el.find('input');
+
+                  $input.off('keyup').on('keyup', function (event) {
+                    search(event, $(this).val());
+                  });
+
+                  $input.off('mouseup').on('mouseup', function (event) {
+                    var $input = $(this),
+                            oldValue = $input.val();
+
+                    if (oldValue === "") {
+                      return;
+                    }
+
+                    setTimeout(function () {
+                      var newValue = $input.val();
+                      if (newValue === "") {
+                        search(event, newValue);
+                      }
+                    }, 1);
+                  });
+
+                  return $el;
+                };
+
+        return template;
+      }
+
+      var options = {
+        filterValues: {price: "$2"},
+        url: "data.json",
+        columns: [
+          {
+            field: "id",
+            title: "ID",
+            filter: {
+              type: "input"
+            }
+          },
+          {
+            field: "name",
+            title: "Item Name",
+            filter: {
+              type: "select",
+              data: []
+            }
+          },
+          {
+            field: "price",
+            title: "Item Price",
+            filter: {
+              type: "select",
+              data: ["$1", "$2", "$3"]
+            }
+          },
+          {
+            field: "amount",
+            title: "Amount",
+            width: 200,
+            filter: {
+              template: getNumberFilterTemplate("amount"),
+              setFilterValue: function ($filter, field, value) {
+                if (value) {
+                  $filter.find('input').val(value.value);
+                }
+              }
+            }
+          }
+        ],
+        filter: true,
+        filterTemplate: {
+          input: function (bootstrapTable, column, isVisible) {
+            return '<input type="text" class="form-control input-sm" data-filter-field="' + column.field + '" style="width: 100%; visibility:' + isVisible + '">';
+          }
+        }
+      };
+
+      var $table = $("#table").bootstrapTable(options);
+      $table.bootstrapTable("setSelect2Data", "name", ["item 1", "item 2", "item 3"]);
+    });
+  </script>
+</head>
+<body>
+<div class="container">
+  <h1>Select2 Filter</h1>
+  <table id="table"></table>
+</div>
+</body>
+</html>