Bootstrap可多选、搜索的下拉列表

冷不防 2022-08-09 18:48 598阅读 0赞

示例图:

可搜索
可搜索

区分大小写搜索

区分大小写搜索

需要引用bootstrap文件,核心文件:bootstrap-multiselect.css、bootstrap-multiselect.js

bootstrap-multiselect.css

  1. .multiselect-container{ position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{ margin:5px}.multiselect-container>li{ padding:0}.multiselect-container>li>a.multiselect-all label{ font-weight:bold}.multiselect-container>li>label.multiselect-group{ margin:0;padding:3px 20px 3px 20px;height:100%;font-weight:bold}.multiselect-container>li>a>label{ margin:0;height:100%;cursor:pointer;font-weight:normal}.multiselect-container>li>a>label.radio,.multiselect-container>li>a>label.checkbox{ margin:0}.multiselect-container>li>a>label>input[type="checkbox"]{ margin-bottom:5px}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{ border-top-left-radius:4px;border-bottom-left-radius:4px}

bootstrap-multiselect.js

  1. /** * Bootstrap Multiselect (https://github.com/davidstutz/bootstrap-multiselect) * * Apache License, Version 2.0: * Copyright (c) 2012 - 2015 David Stutz * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * * BSD 3-Clause License: * Copyright (c) 2012 - 2015 David Stutz * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of David Stutz nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 为什么使用这个js:全选后可以反选 */
  2. !function ($) {
  3. "use strict";// jshint ;_;
  4. if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
  5. ko.bindingHandlers.multiselect = {
  6. after: ['options', 'value', 'selectedOptions'],
  7. init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
  8. var $element = $(element);
  9. var config = ko.toJS(valueAccessor());
  10. $element.multiselect(config);
  11. if (allBindings.has('options')) {
  12. var options = allBindings.get('options');
  13. if (ko.isObservable(options)) {
  14. ko.computed({
  15. read: function () {
  16. options();
  17. setTimeout(function () {
  18. var ms = $element.data('multiselect');
  19. if (ms)
  20. ms.updateOriginalOptions();//Not sure how beneficial this is.
  21. $element.multiselect('rebuild');
  22. }, 1);
  23. },
  24. disposeWhenNodeIsRemoved: element
  25. });
  26. }
  27. }
  28. //value and selectedOptions are two-way, so these will be triggered even by our own actions.
  29. //It needs some way to tell if they are triggered because of us or because of outside change.
  30. //It doesn't loop but it's a waste of processing.
  31. if (allBindings.has('value')) {
  32. var value = allBindings.get('value');
  33. if (ko.isObservable(value)) {
  34. ko.computed({
  35. read: function () {
  36. value();
  37. setTimeout(function () {
  38. $element.multiselect('refresh');
  39. }, 1);
  40. },
  41. disposeWhenNodeIsRemoved: element
  42. }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
  43. }
  44. }
  45. //Switched from arrayChange subscription to general subscription using 'refresh'.
  46. //Not sure performance is any better using 'select' and 'deselect'.
  47. if (allBindings.has('selectedOptions')) {
  48. var selectedOptions = allBindings.get('selectedOptions');
  49. if (ko.isObservable(selectedOptions)) {
  50. ko.computed({
  51. read: function () {
  52. selectedOptions();
  53. setTimeout(function () {
  54. $element.multiselect('refresh');
  55. }, 1);
  56. },
  57. disposeWhenNodeIsRemoved: element
  58. }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
  59. }
  60. }
  61. ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
  62. $element.multiselect('destroy');
  63. });
  64. },
  65. update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
  66. var $element = $(element);
  67. var config = ko.toJS(valueAccessor());
  68. $element.multiselect('setOptions', config);
  69. $element.multiselect('rebuild');
  70. }
  71. };
  72. }
  73. function forEach(array, callback) {
  74. for (var index = 0; index < array.length; ++index) {
  75. callback(array[index], index);
  76. }
  77. }
  78. /** * Constructor to create a new multiselect using the given select. * * @param {jQuery} select * @param {Object} options * @returns {Multiselect} */
  79. function Multiselect(select, options) {
  80. this.$select = $(select);
  81. this.options = this.mergeOptions($.extend({}, options, this.$select.data()));
  82. // Initialization.
  83. // We have to clone to create a new reference.
  84. this.originalOptions = this.$select.clone()[0].options;
  85. this.query = '';
  86. this.searchTimeout = null;
  87. this.lastToggledInput = null
  88. this.options.multiple = this.$select.attr('multiple') === "multiple";
  89. this.options.onChange = $.proxy(this.options.onChange, this);
  90. this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this);
  91. this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this);
  92. this.options.onDropdownShown = $.proxy(this.options.onDropdownShown, this);
  93. this.options.onDropdownHidden = $.proxy(this.options.onDropdownHidden, this);
  94. // Build select all if enabled.
  95. this.buildContainer();
  96. this.buildButton();
  97. this.buildDropdown();
  98. this.buildSelectAll();
  99. this.buildDropdownOptions();
  100. this.buildFilter();
  101. this.updateButtonText();
  102. this.updateSelectAll();
  103. if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {
  104. this.disable();
  105. }
  106. this.$select.hide().after(this.$container);
  107. };
  108. Multiselect.prototype = {
  109. defaults: {
  110. /** * Default text function will either print 'None selected' in case no * option is selected or a list of the selected options up to a length * of 3 selected options. * * @param {jQuery} options * @param {jQuery} select * @returns {String} */
  111. buttonText: function (options, select) {
  112. if (options.length === 0) {
  113. return this.nonSelectedText;
  114. }
  115. else if (this.allSelectedText && options.length == $('option', $(select)).length) {
  116. if (this.selectAllNumber) {
  117. return this.allSelectedText + ' (' + options.length + ')';
  118. }
  119. else {
  120. return this.allSelectedText;
  121. }
  122. }
  123. else if (options.length > this.numberDisplayed) {
  124. return options.length + ' ' + this.nSelectedText;
  125. }
  126. else {
  127. var selected = '';
  128. options.each(function () {
  129. var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
  130. selected += label + ', ';
  131. });
  132. return selected.substr(0, selected.length - 2);
  133. }
  134. },
  135. /** * Updates the title of the button similar to the buttonText function. * * @param {jQuery} options * @param {jQuery} select * @returns { @exp;selected@call;substr} */
  136. buttonTitle: function (options, select) {
  137. if (options.length === 0) {
  138. return this.nonSelectedText;
  139. }
  140. else {
  141. var selected = '';
  142. options.each(function () {
  143. selected += $(this).text() + ', ';
  144. });
  145. return selected.substr(0, selected.length - 2);
  146. }
  147. },
  148. /** * Create a label. * * @param {jQuery} element * @returns {String} */
  149. optionLabel: function (element) {
  150. return $(element).attr('label') || $(element).text();
  151. },
  152. /** * Triggered on change of the multiselect. * * Not triggered when selecting/deselecting options manually. * * @param {jQuery} option * @param {Boolean} checked */
  153. onChange: function (option, checked) {
  154. },
  155. /** * Triggered when the dropdown is shown. * * @param {jQuery} event */
  156. onDropdownShow: function (event) {
  157. },
  158. /** * Triggered when the dropdown is hidden. * * @param {jQuery} event */
  159. onDropdownHide: function (event) {
  160. },
  161. /** * Triggered after the dropdown is shown. * * @param {jQuery} event */
  162. onDropdownShown: function (event) {
  163. },
  164. /** * Triggered after the dropdown is hidden. * * @param {jQuery} event */
  165. onDropdownHidden: function (event) {
  166. },
  167. /** * Triggered on select all. */
  168. onSelectAll: function () {
  169. },
  170. enableHTML: false,
  171. //buttonClass: 'btn btn-default',
  172. buttonClass: 'btn',
  173. inheritClass: false,
  174. buttonWidth: 'auto',
  175. buttonContainer: '<div class="btn-group" style="width:100%" />',
  176. dropRight: false,
  177. selectedClass: 'active',
  178. // Maximum height of the dropdown menu.
  179. // If maximum height is exceeded a scrollbar will be displayed.
  180. maxHeight: false,
  181. checkboxName: false,
  182. includeSelectAllOption: false,
  183. includeSelectAllIfMoreThan: 0,
  184. selectAllText: ' 全选',
  185. selectAllValue: 'multiselect-all',
  186. selectAllName: false,
  187. selectAllNumber: true,
  188. enableFiltering: false,
  189. enableCaseInsensitiveFiltering: false,
  190. enableClickableOptGroups: false,
  191. filterPlaceholder: 'Search',
  192. // possible options: 'text', 'value', 'both'
  193. filterBehavior: 'text',
  194. includeFilterClearBtn: true,
  195. preventInputChangeEvent: false,
  196. nonSelectedText: '请选择',
  197. nSelectedText: 'selected',
  198. allSelectedText: 'All selected',
  199. numberDisplayed: 3,
  200. disableIfEmpty: false,
  201. templates: {
  202. button: '<button type="button" class="multiselect dropdown-toggle form-control" data-toggle="dropdown"><span class="multiselect-selected-text"></span> <b class="caret"></b></button>',
  203. ul: '<ul class="multiselect-container dropdown-menu"></ul>',
  204. filter: '<li class="multiselect-item filter"><div class="input-group"><span class="input-group-addon"><i class="fa fa-search"></i></span><input class="form-control multiselect-search" type="text"></div></li>',
  205. filterClearBtn: '<span class="input-group-btn"><button class="btn btn-default multiselect-clear-filter" type="button"><i class="fa fa-times-circle" ></i></button></span>',
  206. li: '<li><a tabindex="0"><label></label></a></li>',
  207. divider: '<li class="multiselect-item divider"></li>',
  208. liGroup: '<li class="multiselect-item multiselect-group"><label></label></li>'
  209. }
  210. },
  211. constructor: Multiselect,
  212. /** * Builds the container of the multiselect. */
  213. buildContainer: function () {
  214. this.$container = $(this.options.buttonContainer);
  215. this.$container.on('show.bs.dropdown', this.options.onDropdownShow);
  216. this.$container.on('hide.bs.dropdown', this.options.onDropdownHide);
  217. this.$container.on('shown.bs.dropdown', this.options.onDropdownShown);
  218. this.$container.on('hidden.bs.dropdown', this.options.onDropdownHidden);
  219. },
  220. /** * Builds the button of the multiselect. */
  221. buildButton: function () {
  222. this.$button = $(this.options.templates.button).addClass(this.options.buttonClass);
  223. if (this.$select.attr('class') && this.options.inheritClass) {
  224. this.$button.addClass(this.$select.attr('class'));
  225. }
  226. // Adopt active state.
  227. if (this.$select.prop('disabled')) {
  228. this.disable();
  229. }
  230. else {
  231. this.enable();
  232. }
  233. // Manually add button width if set.
  234. if (this.options.buttonWidth && this.options.buttonWidth !== 'auto') {
  235. this.$button.css({
  236. 'width': this.options.buttonWidth,
  237. 'overflow': 'hidden',
  238. 'text-overflow': 'ellipsis'
  239. });
  240. this.$container.css({
  241. 'width': this.options.buttonWidth
  242. });
  243. }
  244. // Keep the tab index from the select.
  245. var tabindex = this.$select.attr('tabindex');
  246. if (tabindex) {
  247. this.$button.attr('tabindex', tabindex);
  248. }
  249. this.$container.prepend(this.$button);
  250. },
  251. /** * Builds the ul representing the dropdown menu. */
  252. buildDropdown: function () {
  253. // Build ul.
  254. this.$ul = $(this.options.templates.ul);
  255. if (this.options.dropRight) {
  256. this.$ul.addClass('pull-right');
  257. }
  258. // Set max height of dropdown menu to activate auto scrollbar.
  259. if (this.options.maxHeight) {
  260. // TODO: Add a class for this option to move the css declarations.
  261. this.$ul.css({
  262. 'max-height': this.options.maxHeight + 'px',
  263. 'overflow-y': 'auto',
  264. 'overflow-x': 'hidden'
  265. });
  266. }
  267. this.$container.append(this.$ul);
  268. },
  269. /** * Build the dropdown options and binds all nessecary events. * * Uses createDivider and createOptionValue to create the necessary options. */
  270. buildDropdownOptions: function () {
  271. this.$select.children().each($.proxy(function (index, element) {
  272. var $element = $(element);
  273. // Support optgroups and options without a group simultaneously.
  274. var tag = $element.prop('tagName')
  275. .toLowerCase();
  276. if ($element.prop('value') === this.options.selectAllValue) {
  277. return;
  278. }
  279. if (tag === 'optgroup') {
  280. this.createOptgroup(element);
  281. }
  282. else if (tag === 'option') {
  283. if ($element.data('role') === 'divider') {
  284. this.createDivider();
  285. }
  286. else {
  287. this.createOptionValue(element);
  288. }
  289. }
  290. // Other illegal tags will be ignored.
  291. }, this));
  292. // Bind the change event on the dropdown elements.
  293. $('li input', this.$ul).on('change', $.proxy(function (event) {
  294. var $target = $(event.target);
  295. var checked = $target.prop('checked') || false;
  296. var isSelectAllOption = $target.val() === this.options.selectAllValue;
  297. // Apply or unapply the configured selected class.
  298. if (this.options.selectedClass) {
  299. if (checked) {
  300. $target.closest('li')
  301. .addClass(this.options.selectedClass);
  302. }
  303. else {
  304. $target.closest('li')
  305. .removeClass(this.options.selectedClass);
  306. }
  307. }
  308. // Get the corresponding option.
  309. var value = $target.val();
  310. var $option = this.getOptionByValue(value);
  311. var $optionsNotThis = $('option', this.$select).not($option);
  312. var $checkboxesNotThis = $('input', this.$container).not($target);
  313. if (isSelectAllOption) {
  314. if (checked) {
  315. this.selectAll();
  316. }
  317. else {
  318. this.deselectAll();
  319. }
  320. }
  321. if (!isSelectAllOption) {
  322. if (checked) {
  323. $option.prop('selected', true);
  324. if (this.options.multiple) {
  325. // Simply select additional option.
  326. $option.prop('selected', true);
  327. }
  328. else {
  329. // Unselect all other options and corresponding checkboxes.
  330. if (this.options.selectedClass) {
  331. $($checkboxesNotThis).closest('li').removeClass(this.options.selectedClass);
  332. }
  333. $($checkboxesNotThis).prop('checked', false);
  334. $optionsNotThis.prop('selected', false);
  335. // It's a single selection, so close.
  336. this.$button.click();
  337. }
  338. if (this.options.selectedClass === "active") {
  339. $optionsNotThis.closest("a").css("outline", "");
  340. }
  341. }
  342. else {
  343. // Unselect option.
  344. $option.prop('selected', false);
  345. }
  346. }
  347. this.$select.change();
  348. this.updateButtonText();
  349. this.updateSelectAll();
  350. this.options.onChange($option, checked);
  351. if (this.options.preventInputChangeEvent) {
  352. return false;
  353. }
  354. }, this));
  355. $('li a', this.$ul).on('mousedown', function (e) {
  356. if (e.shiftKey) {
  357. // Prevent selecting text by Shift+click
  358. return false;
  359. }
  360. });
  361. $('li a', this.$ul).on('touchstart click', $.proxy(function (event) {
  362. event.stopPropagation();
  363. var $target = $(event.target);
  364. if (event.shiftKey && this.options.multiple) {
  365. if ($target.is("label")) { // Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431)
  366. event.preventDefault();
  367. $target = $target.find("input");
  368. $target.prop("checked", !$target.prop("checked"));
  369. }
  370. var checked = $target.prop('checked') || false;
  371. if (this.lastToggledInput !== null && this.lastToggledInput !== $target) { // Make sure we actually have a range
  372. var from = $target.closest("li").index();
  373. var to = this.lastToggledInput.closest("li").index();
  374. if (from > to) { // Swap the indices
  375. var tmp = to;
  376. to = from;
  377. from = tmp;
  378. }
  379. // Make sure we grab all elements since slice excludes the last index
  380. ++to;
  381. // Change the checkboxes and underlying options
  382. var range = this.$ul.find("li").slice(from, to).find("input");
  383. range.prop('checked', checked);
  384. if (this.options.selectedClass) {
  385. range.closest('li')
  386. .toggleClass(this.options.selectedClass, checked);
  387. }
  388. for (var i = 0, j = range.length; i < j; i++) {
  389. var $checkbox = $(range[i]);
  390. var $option = this.getOptionByValue($checkbox.val());
  391. $option.prop('selected', checked);
  392. }
  393. }
  394. // Trigger the select "change" event
  395. $target.trigger("change");
  396. }
  397. // Remembers last clicked option
  398. if ($target.is("input") && !$target.closest("li").is(".multiselect-item")) {
  399. this.lastToggledInput = $target;
  400. }
  401. $target.blur();
  402. }, this));
  403. // Keyboard support.
  404. this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function (event) {
  405. if ($('input[type="text"]', this.$container).is(':focus')) {
  406. return;
  407. }
  408. if (event.keyCode === 9 && this.$container.hasClass('open')) {
  409. this.$button.click();
  410. }
  411. else {
  412. var $items = $(this.$container).find("li:not(.divider):not(.disabled) a").filter(":visible");
  413. if (!$items.length) {
  414. return;
  415. }
  416. var index = $items.index($items.filter(':focus'));
  417. // Navigation up.
  418. if (event.keyCode === 38 && index > 0) {
  419. index--;
  420. }
  421. // Navigate down.
  422. else if (event.keyCode === 40 && index < $items.length - 1) {
  423. index++;
  424. }
  425. else if (!~index) {
  426. index = 0;
  427. }
  428. var $current = $items.eq(index);
  429. $current.focus();
  430. if (event.keyCode === 32 || event.keyCode === 13) {
  431. var $checkbox = $current.find('input');
  432. $checkbox.prop("checked", !$checkbox.prop("checked"));
  433. $checkbox.change();
  434. }
  435. event.stopPropagation();
  436. event.preventDefault();
  437. }
  438. }, this));
  439. if (this.options.enableClickableOptGroups && this.options.multiple) {
  440. $('li.multiselect-group', this.$ul).on('click', $.proxy(function (event) {
  441. event.stopPropagation();
  442. var group = $(event.target).parent();
  443. // Search all option in optgroup
  444. var $options = group.nextUntil('li.multiselect-group');
  445. var $visibleOptions = $options.filter(":visible:not(.disabled)");
  446. // check or uncheck items
  447. var allChecked = true;
  448. var optionInputs = $visibleOptions.find('input');
  449. optionInputs.each(function () {
  450. allChecked = allChecked && $(this).prop('checked');
  451. });
  452. optionInputs.prop('checked', !allChecked).trigger('change');
  453. }, this));
  454. }
  455. },
  456. /** * Create an option using the given select option. * * @param {jQuery} element */
  457. createOptionValue: function (element) {
  458. var $element = $(element);
  459. if ($element.is(':selected')) {
  460. $element.prop('selected', true);
  461. }
  462. // Support the label attribute on options.
  463. var label = this.options.optionLabel(element);
  464. var value = $element.val();
  465. var inputType = this.options.multiple ? "checkbox" : "radio";
  466. var $li = $(this.options.templates.li);
  467. var $label = $('label', $li);
  468. $label.addClass(inputType);
  469. if (this.options.enableHTML) {
  470. $label.html(" " + label);
  471. }
  472. else {
  473. $label.text(" " + label);
  474. }
  475. var $checkbox = $('<input/>').attr('type', inputType);
  476. if (this.options.checkboxName) {
  477. $checkbox.attr('name', this.options.checkboxName);
  478. }
  479. $label.prepend($checkbox);
  480. var selected = $element.prop('selected') || false;
  481. $checkbox.val(value);
  482. if (value === this.options.selectAllValue) {
  483. $li.addClass("multiselect-item multiselect-all");
  484. $checkbox.parent().parent()
  485. .addClass('multiselect-all');
  486. }
  487. $label.attr('title', $element.attr('title'));
  488. this.$ul.append($li);
  489. if ($element.is(':disabled')) {
  490. $checkbox.attr('disabled', 'disabled')
  491. .prop('disabled', true)
  492. .closest('a')
  493. .attr("tabindex", "-1")
  494. .closest('li')
  495. .addClass('disabled');
  496. }
  497. $checkbox.prop('checked', selected);
  498. if (selected && this.options.selectedClass) {
  499. $checkbox.closest('li')
  500. .addClass(this.options.selectedClass);
  501. }
  502. },
  503. /** * Creates a divider using the given select option. * * @param {jQuery} element */
  504. createDivider: function (element) {
  505. var $divider = $(this.options.templates.divider);
  506. this.$ul.append($divider);
  507. },
  508. /** * Creates an optgroup. * * @param {jQuery} group */
  509. createOptgroup: function (group) {
  510. var groupName = $(group).prop('label');
  511. // Add a header for the group.
  512. var $li = $(this.options.templates.liGroup);
  513. if (this.options.enableHTML) {
  514. $('label', $li).html(groupName);
  515. }
  516. else {
  517. $('label', $li).text(groupName);
  518. }
  519. if (this.options.enableClickableOptGroups) {
  520. $li.addClass('multiselect-group-clickable');
  521. }
  522. this.$ul.append($li);
  523. if ($(group).is(':disabled')) {
  524. $li.addClass('disabled');
  525. }
  526. // Add the options of the group.
  527. $('option', group).each($.proxy(function (index, element) {
  528. this.createOptionValue(element);
  529. }, this));
  530. },
  531. /** * Build the selct all. * * Checks if a select all has already been created. */
  532. buildSelectAll: function () {
  533. if (typeof this.options.selectAllValue === 'number') {
  534. this.options.selectAllValue = this.options.selectAllValue.toString();
  535. }
  536. var alreadyHasSelectAll = this.hasSelectAll();
  537. if (!alreadyHasSelectAll && this.options.includeSelectAllOption && this.options.multiple
  538. && $('option', this.$select).length > this.options.includeSelectAllIfMoreThan) {
  539. // Check whether to add a divider after the select all.
  540. if (this.options.includeSelectAllDivider) {
  541. this.$ul.prepend($(this.options.templates.divider));
  542. }
  543. var $li = $(this.options.templates.li);
  544. $('label', $li).addClass("checkbox");
  545. if (this.options.enableHTML) {
  546. $('label', $li).html(" " + this.options.selectAllText);
  547. }
  548. else {
  549. $('label', $li).text(" " + this.options.selectAllText);
  550. }
  551. if (this.options.selectAllName) {
  552. $('label', $li).prepend('<input type="checkbox" name="' + this.options.selectAllName + '" />');
  553. }
  554. else {
  555. $('label', $li).prepend('<input type="checkbox" />');
  556. }
  557. var $checkbox = $('input', $li);
  558. $checkbox.val(this.options.selectAllValue);
  559. $li.addClass("multiselect-item multiselect-all");
  560. $checkbox.parent().parent()
  561. .addClass('multiselect-all');
  562. this.$ul.prepend($li);
  563. $checkbox.prop('checked', false);
  564. }
  565. },
  566. /** * Builds the filter. */
  567. buildFilter: function () {
  568. // Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength.
  569. if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
  570. var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering);
  571. if (this.$select.find('option').length >= enableFilterLength) {
  572. this.$filter = $(this.options.templates.filter);
  573. $('input', this.$filter).attr('placeholder', this.options.filterPlaceholder);
  574. // Adds optional filter clear button
  575. if (this.options.includeFilterClearBtn) {
  576. var clearBtn = $(this.options.templates.filterClearBtn);
  577. clearBtn.on('click', $.proxy(function (event) {
  578. clearTimeout(this.searchTimeout);
  579. this.$filter.find('.multiselect-search').val('');
  580. $('li', this.$ul).show().removeClass("filter-hidden");
  581. this.updateSelectAll();
  582. }, this));
  583. this.$filter.find('.input-group').append(clearBtn);
  584. }
  585. this.$ul.prepend(this.$filter);
  586. this.$filter.val(this.query).on('click', function (event) {
  587. event.stopPropagation();
  588. }).on('input keydown', $.proxy(function (event) {
  589. // Cancel enter key default behaviour
  590. if (event.which === 13) {
  591. event.preventDefault();
  592. }
  593. // This is useful to catch "keydown" events after the browser has updated the control.
  594. clearTimeout(this.searchTimeout);
  595. this.searchTimeout = this.asyncFunction($.proxy(function () {
  596. if (this.query !== event.target.value) {
  597. this.query = event.target.value;
  598. var currentGroup, currentGroupVisible;
  599. $.each($('li', this.$ul), $.proxy(function (index, element) {
  600. var value = $('input', element).length > 0 ? $('input', element).val() : "";
  601. var text = $('label', element).text();
  602. var filterCandidate = '';
  603. if ((this.options.filterBehavior === 'text')) {
  604. filterCandidate = text;
  605. }
  606. else if ((this.options.filterBehavior === 'value')) {
  607. filterCandidate = value;
  608. }
  609. else if (this.options.filterBehavior === 'both') {
  610. filterCandidate = text + '\n' + value;
  611. }
  612. if (value !== this.options.selectAllValue && text) {
  613. // By default lets assume that element is not
  614. // interesting for this search.
  615. var showElement = false;
  616. if (this.options.enableCaseInsensitiveFiltering && filterCandidate.toLowerCase().indexOf(this.query.toLowerCase()) > -1) {
  617. showElement = true;
  618. }
  619. else if (filterCandidate.indexOf(this.query) > -1) {
  620. showElement = true;
  621. }
  622. // Toggle current element (group or group item) according to showElement boolean.
  623. $(element).toggle(showElement).toggleClass('filter-hidden', !showElement);
  624. // Differentiate groups and group items.
  625. if ($(element).hasClass('multiselect-group')) {
  626. // Remember group status.
  627. currentGroup = element;
  628. currentGroupVisible = showElement;
  629. }
  630. else {
  631. // Show group name when at least one of its items is visible.
  632. if (showElement) {
  633. $(currentGroup).show().removeClass('filter-hidden');
  634. }
  635. // Show all group items when group name satisfies filter.
  636. if (!showElement && currentGroupVisible) {
  637. $(element).show().removeClass('filter-hidden');
  638. }
  639. }
  640. }
  641. }, this));
  642. }
  643. this.updateSelectAll();
  644. }, this), 300, this);
  645. }, this));
  646. }
  647. }
  648. },
  649. /** * Unbinds the whole plugin. */
  650. destroy: function () {
  651. this.$container.remove();
  652. this.$select.show();
  653. this.$select.data('multiselect', null);
  654. },
  655. /** * Refreshs the multiselect based on the selected options of the select. */
  656. refresh: function () {
  657. $('option', this.$select).each($.proxy(function (index, element) {
  658. var $input = $('li input', this.$ul).filter(function () {
  659. return $(this).val() === $(element).val();
  660. });
  661. if ($(element).is(':selected')) {
  662. $input.prop('checked', true);
  663. if (this.options.selectedClass) {
  664. $input.closest('li')
  665. .addClass(this.options.selectedClass);
  666. }
  667. }
  668. else {
  669. $input.prop('checked', false);
  670. if (this.options.selectedClass) {
  671. $input.closest('li')
  672. .removeClass(this.options.selectedClass);
  673. }
  674. }
  675. if ($(element).is(":disabled")) {
  676. $input.attr('disabled', 'disabled')
  677. .prop('disabled', true)
  678. .closest('li')
  679. .addClass('disabled');
  680. }
  681. else {
  682. $input.prop('disabled', false)
  683. .closest('li')
  684. .removeClass('disabled');
  685. }
  686. }, this));
  687. this.updateButtonText();
  688. this.updateSelectAll();
  689. },
  690. /** * Select all options of the given values. * * If triggerOnChange is set to true, the on change event is triggered if * and only if one value is passed. * * @param {Array} selectValues * @param {Boolean} triggerOnChange */
  691. select: function (selectValues, triggerOnChange) {
  692. if (!$.isArray(selectValues)) {
  693. selectValues = [selectValues];
  694. }
  695. for (var i = 0; i < selectValues.length; i++) {
  696. var value = selectValues[i];
  697. if (value === null || value === undefined) {
  698. continue;
  699. }
  700. var $option = this.getOptionByValue(value);
  701. var $checkbox = this.getInputByValue(value);
  702. if ($option === undefined || $checkbox === undefined) {
  703. continue;
  704. }
  705. if (!this.options.multiple) {
  706. this.deselectAll(false);
  707. }
  708. if (this.options.selectedClass) {
  709. $checkbox.closest('li')
  710. .addClass(this.options.selectedClass);
  711. }
  712. $checkbox.prop('checked', true);
  713. $option.prop('selected', true);
  714. }
  715. this.updateButtonText();
  716. this.updateSelectAll();
  717. if (triggerOnChange && selectValues.length === 1) {
  718. this.options.onChange($option, true);
  719. }
  720. },
  721. /** * Clears all selected items. */
  722. clearSelection: function () {
  723. this.deselectAll(false);
  724. this.updateButtonText();
  725. this.updateSelectAll();
  726. },
  727. /** * Deselects all options of the given values. * * If triggerOnChange is set to true, the on change event is triggered, if * and only if one value is passed. * * @param {Array} deselectValues * @param {Boolean} triggerOnChange */
  728. deselect: function (deselectValues, triggerOnChange) {
  729. if (!$.isArray(deselectValues)) {
  730. deselectValues = [deselectValues];
  731. }
  732. for (var i = 0; i < deselectValues.length; i++) {
  733. var value = deselectValues[i];
  734. if (value === null || value === undefined) {
  735. continue;
  736. }
  737. var $option = this.getOptionByValue(value);
  738. var $checkbox = this.getInputByValue(value);
  739. if ($option === undefined || $checkbox === undefined) {
  740. continue;
  741. }
  742. if (this.options.selectedClass) {
  743. $checkbox.closest('li')
  744. .removeClass(this.options.selectedClass);
  745. }
  746. $checkbox.prop('checked', false);
  747. $option.prop('selected', false);
  748. }
  749. this.updateButtonText();
  750. this.updateSelectAll();
  751. if (triggerOnChange && deselectValues.length === 1) {
  752. this.options.onChange($option, false);
  753. }
  754. },
  755. /** * Selects all enabled & visible options. * * If justVisible is true or not specified, only visible options are selected. * * @param {Boolean} justVisible * @param {Boolean} triggerOnSelectAll */
  756. selectAll: function (justVisible, triggerOnSelectAll) {
  757. var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
  758. var allCheckboxes = $("li input[type='checkbox']:enabled", this.$ul);
  759. var visibleCheckboxes = allCheckboxes.filter(":visible");
  760. var allCheckboxesCount = allCheckboxes.length;
  761. var visibleCheckboxesCount = visibleCheckboxes.length;
  762. if (justVisible) {
  763. visibleCheckboxes.prop('checked', true);
  764. $("li:not(.divider):not(.disabled)", this.$ul).filter(":visible").addClass(this.options.selectedClass);
  765. }
  766. else {
  767. allCheckboxes.prop('checked', true);
  768. $("li:not(.divider):not(.disabled)", this.$ul).addClass(this.options.selectedClass);
  769. }
  770. if (allCheckboxesCount === visibleCheckboxesCount || justVisible === false) {
  771. $("option:enabled", this.$select).prop('selected', true);
  772. }
  773. else {
  774. var values = visibleCheckboxes.map(function () {
  775. return $(this).val();
  776. }).get();
  777. $("option:enabled", this.$select).filter(function (index) {
  778. return $.inArray($(this).val(), values) !== -1;
  779. }).prop('selected', true);
  780. }
  781. if (triggerOnSelectAll) {
  782. this.options.onSelectAll();
  783. }
  784. },
  785. /** * Deselects all options. * * If justVisible is true or not specified, only visible options are deselected. * * @param {Boolean} justVisible */
  786. deselectAll: function (justVisible) {
  787. var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
  788. if (justVisible) {
  789. var visibleCheckboxes = $("li input[type='checkbox']:not(:disabled)", this.$ul).filter(":visible");
  790. visibleCheckboxes.prop('checked', false);
  791. var values = visibleCheckboxes.map(function () {
  792. return $(this).val();
  793. }).get();
  794. $("option:enabled", this.$select).filter(function (index) {
  795. return $.inArray($(this).val(), values) !== -1;
  796. }).prop('selected', false);
  797. if (this.options.selectedClass) {
  798. $("li:not(.divider):not(.disabled)", this.$ul).filter(":visible").removeClass(this.options.selectedClass);
  799. }
  800. }
  801. else {
  802. $("li input[type='checkbox']:enabled", this.$ul).prop('checked', false);
  803. $("option:enabled", this.$select).prop('selected', false);
  804. if (this.options.selectedClass) {
  805. $("li:not(.divider):not(.disabled)", this.$ul).removeClass(this.options.selectedClass);
  806. }
  807. }
  808. },
  809. /** * Rebuild the plugin. * * Rebuilds the dropdown, the filter and the select all option. */
  810. rebuild: function () {
  811. this.$ul.html('');
  812. // Important to distinguish between radios and checkboxes.
  813. this.options.multiple = this.$select.attr('multiple') === "multiple";
  814. this.buildSelectAll();
  815. this.buildDropdownOptions();
  816. this.buildFilter();
  817. this.updateButtonText();
  818. this.updateSelectAll();
  819. if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {
  820. this.disable();
  821. }
  822. else {
  823. this.enable();
  824. }
  825. if (this.options.dropRight) {
  826. this.$ul.addClass('pull-right');
  827. }
  828. },
  829. /** * The provided data will be used to build the dropdown. */
  830. dataprovider: function (dataprovider) {
  831. var groupCounter = 0;
  832. var $select = this.$select.empty();
  833. $.each(dataprovider, function (index, option) {
  834. var $tag;
  835. if ($.isArray(option.children)) { // create optiongroup tag
  836. groupCounter++;
  837. $tag = $('<optgroup/>').attr({
  838. label: option.label || 'Group ' + groupCounter,
  839. disabled: !!option.disabled
  840. });
  841. forEach(option.children, function (subOption) { // add children option tags
  842. $tag.append($('<option/>').attr({
  843. value: subOption.value,
  844. label: subOption.label || subOption.value,
  845. title: subOption.title,
  846. selected: !!subOption.selected,
  847. disabled: !!subOption.disabled
  848. }));
  849. });
  850. }
  851. else {
  852. $tag = $('<option/>').attr({
  853. value: option.value,
  854. label: option.label || option.value,
  855. title: option.title,
  856. selected: !!option.selected,
  857. disabled: !!option.disabled
  858. });
  859. }
  860. $select.append($tag);
  861. });
  862. this.rebuild();
  863. },
  864. /** * Enable the multiselect. */
  865. enable: function () {
  866. this.$select.prop('disabled', false);
  867. this.$button.prop('disabled', false)
  868. .removeClass('disabled');
  869. },
  870. /** * Disable the multiselect. */
  871. disable: function () {
  872. this.$select.prop('disabled', true);
  873. this.$button.prop('disabled', true)
  874. .addClass('disabled');
  875. },
  876. /** * Set the options. * * @param {Array} options */
  877. setOptions: function (options) {
  878. this.options = this.mergeOptions(options);
  879. },
  880. /** * Merges the given options with the default options. * * @param {Array} options * @returns {Array} */
  881. mergeOptions: function (options) {
  882. return $.extend(true, {}, this.defaults, this.options, options);
  883. },
  884. /** * Checks whether a select all checkbox is present. * * @returns {Boolean} */
  885. hasSelectAll: function () {
  886. return $('li.multiselect-all', this.$ul).length > 0;
  887. },
  888. /** * Updates the select all checkbox based on the currently displayed and selected checkboxes. */
  889. updateSelectAll: function () {
  890. if (this.hasSelectAll()) {
  891. var allBoxes = $("li:not(.multiselect-item):not(.filter-hidden) input:enabled", this.$ul);
  892. var allBoxesLength = allBoxes.length;
  893. var checkedBoxesLength = allBoxes.filter(":checked").length;
  894. var selectAllLi = $("li.multiselect-all", this.$ul);
  895. var selectAllInput = selectAllLi.find("input");
  896. if (checkedBoxesLength > 0 && checkedBoxesLength === allBoxesLength) {
  897. selectAllInput.prop("checked", true);
  898. selectAllLi.addClass(this.options.selectedClass);
  899. this.options.onSelectAll();
  900. }
  901. else {
  902. selectAllInput.prop("checked", false);
  903. selectAllLi.removeClass(this.options.selectedClass);
  904. }
  905. }
  906. },
  907. /** * Update the button text and its title based on the currently selected options. */
  908. updateButtonText: function () {
  909. var options = this.getSelected();
  910. // First update the displayed button text.
  911. if (this.options.enableHTML) {
  912. $('.multiselect .multiselect-selected-text', this.$container).html(this.options.buttonText(options, this.$select));
  913. }
  914. else {
  915. $('.multiselect .multiselect-selected-text', this.$container).text(this.options.buttonText(options, this.$select));
  916. }
  917. // Now update the title attribute of the button.
  918. $('.multiselect', this.$container).attr('title', this.options.buttonTitle(options, this.$select));
  919. },
  920. /** * Get all selected options. * * @returns {jQUery} */
  921. getSelected: function () {
  922. return $('option', this.$select).filter(":selected");
  923. },
  924. /** * Gets a select option by its value. * * @param {String} value * @returns {jQuery} */
  925. getOptionByValue: function (value) {
  926. var options = $('option', this.$select);
  927. var valueToCompare = value.toString();
  928. for (var i = 0; i < options.length; i = i + 1) {
  929. var option = options[i];
  930. if (option.value === valueToCompare) {
  931. return $(option);
  932. }
  933. }
  934. },
  935. /** * Get the input (radio/checkbox) by its value. * * @param {String} value * @returns {jQuery} */
  936. getInputByValue: function (value) {
  937. var checkboxes = $('li input', this.$ul);
  938. var valueToCompare = value.toString();
  939. for (var i = 0; i < checkboxes.length; i = i + 1) {
  940. var checkbox = checkboxes[i];
  941. if (checkbox.value === valueToCompare) {
  942. return $(checkbox);
  943. }
  944. }
  945. },
  946. /** * Used for knockout integration. */
  947. updateOriginalOptions: function () {
  948. this.originalOptions = this.$select.clone()[0].options;
  949. },
  950. asyncFunction: function (callback, timeout, self) {
  951. var args = Array.prototype.slice.call(arguments, 3);
  952. return setTimeout(function () {
  953. callback.apply(self || window, args);
  954. }, timeout);
  955. },
  956. setAllSelectedText: function (allSelectedText) {
  957. this.options.allSelectedText = allSelectedText;
  958. this.updateButtonText();
  959. }
  960. };
  961. $.fn.multiselect = function (option, parameter, extraOptions) {
  962. return this.each(function () {
  963. var data = $(this).data('multiselect');
  964. var options = typeof option === 'object' && option;
  965. // Initialize the multiselect.
  966. if (!data) {
  967. data = new Multiselect(this, options);
  968. $(this).data('multiselect', data);
  969. }
  970. // Call multiselect method.
  971. if (typeof option === 'string') {
  972. data[option](parameter, extraOptions);
  973. if (option === 'destroy') {
  974. $(this).data('multiselect', false);
  975. }
  976. }
  977. });
  978. };
  979. $.fn.multiselect.Constructor = Multiselect;
  980. $(function () {
  981. $("select[data-role=multiselect]").multiselect();
  982. });
  983. }(window.jQuery);

HTML代码:

  1. <asp:DropDownList runat="server" CssClass="form-control" multiple="multiple" ID="Caccey_location_ddl">
  2. </asp:DropDownList>
  3. <asp:DropDownList runat="server" CssClass="form-control" ID="cabinet_code_ddl" multiple="multiple" >
  4. </asp:DropDownList>
  5. <script type="text/javascript"> $(document).ready(function () { $('#MainContent_Caccey_location_ddl').multiselect({ includeSelectAllOption: true, enableFiltering: true, maxHeight: 400, numberDisplayed: 1 }); $('#MainContent_cabinet_code_ddl').multiselect({ includeSelectAllOption: true, enableFiltering: true, maxHeight: 400, numberDisplayed: 1, enableCaseInsensitiveFiltering: true }); });

清空勾选项:

  1. $('option', $('#MainContent_cabinet_code_ddl')).each(function (element) {
  2. $(this).removeAttr('selected').prop('selected', false);
  3. });
  4. $('#MainContent_cabinet_code_ddl').multiselect('refresh');

清空勾选项(先销毁,再绑定):

  1. $('#MainContent_cabinet_code_ddl').multiselect('destroy');
  2. $('#MainContent_cabinet_code_ddl').multiselect({
  3. includeSelectAllOption: true,
  4. enableFiltering: true,
  5. maxHeight: 400,
  6. numberDisplayed: 1
  7. });

获取勾选项数据:

  1. var cabinet_code = "";
  2. $("#MainContent_cabinet_code_ddl").next().find(".multiselect-container .active").each(function () {
  3. var value = $(this).find(" a label input").val();
  4. if (value != "" && value != "multiselect-all" && (typeof (value) != "undefined")) {
  5. cabinet_code += "'" + value + "',";
  6. }
  7. })

动态切换下拉框:

这里写图片描述

  1. function ReservationTypeChange(obj) {
  2. $("#GuestMenuResult_ddl").html("");
  3. $('#GuestMenuResult_ddl').multiselect('dataprovider', '');
  4. var code = $.trim($(obj).val());
  5. if (code != "") {
  6. $.ajax({
  7. async: false,
  8. cache: false,
  9. url: "../AjaxPage/GetAjax.aspx?z=GetPubGuestMenuInfoBycode&code=" + escape(code) + "",
  10. dataType: 'json',
  11. success: function (data) {
  12. if (data == null) {
  13. $("#GuestMenuResult_ddl").html("");
  14. }
  15. else if (data.msg == 'OffLineLogin') {
  16. OffLineLoginTimeoutNoTop();
  17. }
  18. else if (data.msg == 'login_timeout') {
  19. LoginTimeout();
  20. }
  21. else if (data != null && data.msg != 'login_timeout') {
  22. var options = [];
  23. options.push({ label: '全部', value: 'pleaseselect', selected: true });
  24. if (data["GuestMenuInfo"] != null && data["GuestMenuInfo"] != "") {
  25. for (var i = 0; i < data["GuestMenuInfo"].length; i++) {
  26. var model = data["GuestMenuInfo"][i];
  27. options.push({ label: $.trim(model.name), value: $.trim(model.id) });
  28. }
  29. $('#GuestMenuResult_ddl').multiselect('dataprovider', options);
  30. }
  31. }
  32. },
  33. error: function (msg) {
  34. $("#GuestMenuResult_ddl").html("");
  35. }
  36. });
  37. }
  38. }

发表评论

表情:
评论列表 (有 0 条评论,598人围观)

还没有评论,来说两句吧...

相关阅读