mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-21 06:56:34 +02:00
Ability to disable sorting of choices/groups
This commit is contained in:
parent
59977af5d3
commit
aff165e4a1
|
@ -41,6 +41,7 @@ A vanilla, lightweight (~15kb gzipped 🎉), configurable select box/text input
|
|||
search: true,
|
||||
flip: true,
|
||||
regexFilter: null,
|
||||
shouldSort: true,
|
||||
sortFilter: sortByAlpha,
|
||||
sortFields: ['label', 'value'],
|
||||
placeholder: true,
|
||||
|
@ -225,6 +226,13 @@ Pass an array of objects:
|
|||
|
||||
**Usage:** A filter that will need to pass for a user to successfully add an item.
|
||||
|
||||
### shouldSort
|
||||
**Type:** `Boolean` **Default:** `true`
|
||||
|
||||
**Input types affected:** `select-one`, `select-multiple`
|
||||
|
||||
**Usage:** Whether choices should be sorted. If false, choices will appear in the order they were given.
|
||||
|
||||
### sortFilter
|
||||
**Type:** `Function` **Default:** sortByAlpha
|
||||
|
||||
|
|
272
assets/scripts/dist/choices.js
vendored
272
assets/scripts/dist/choices.js
vendored
|
@ -104,6 +104,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Retrieve triggering element (i.e. element with 'data-choice' trigger)
|
||||
this.passedElement = (0, _utils.isType)('String', element) ? document.querySelector(element) : element;
|
||||
|
||||
// If element has already been initalised with Choices, return it silently
|
||||
if (this.passedElement.getAttribute('data-choice') === 'active') return;
|
||||
|
||||
var defaultConfig = {
|
||||
items: [],
|
||||
choices: [],
|
||||
|
@ -118,6 +124,7 @@
|
|||
search: true,
|
||||
flip: true,
|
||||
regexFilter: null,
|
||||
shouldSort: true,
|
||||
sortFilter: _utils.sortByAlpha,
|
||||
sortFields: ['label', 'value'],
|
||||
placeholder: true,
|
||||
|
@ -172,12 +179,14 @@
|
|||
this.currentState = {};
|
||||
this.prevState = {};
|
||||
this.currentValue = '';
|
||||
|
||||
// Retrieve triggering element (i.e. element with 'data-choice' trigger)
|
||||
this.passedElement = (0, _utils.isType)('String', element) ? document.querySelector(element) : element;
|
||||
|
||||
this.highlightPosition = 0;
|
||||
|
||||
// Track searching
|
||||
this.canSearch = this.config.search;
|
||||
// Track tapping
|
||||
this.wasTap = true;
|
||||
// Focus containerOuter but not show dropdown if true
|
||||
this.focusAndHideDropdown = false;
|
||||
|
||||
// Assing preset choices from passed object
|
||||
this.presetChoices = this.config.choices;
|
||||
|
@ -209,25 +218,17 @@
|
|||
this._onPaste = this._onPaste.bind(this);
|
||||
this._onInput = this._onInput.bind(this);
|
||||
|
||||
// Focus containerOuter but not show dropdown if true
|
||||
this.focusAndHideDropdown = false;
|
||||
|
||||
// Monitor touch taps/scrolls
|
||||
this.wasTap = true;
|
||||
|
||||
// Cutting the mustard
|
||||
var cuttingTheMustard = 'querySelector' in document && 'addEventListener' in document && 'classList' in document.createElement('div');
|
||||
if (!cuttingTheMustard) console.error('Choices: Your browser doesn\'t support Choices');
|
||||
|
||||
// Input type check
|
||||
var canInit = this.passedElement && (0, _utils.isElement)(this.passedElement) && ['select-one', 'select-multiple', 'text'].some(function (type) {
|
||||
var isValidElement = this.passedElement && (0, _utils.isElement)(this.passedElement);
|
||||
var isValidType = ['select-one', 'select-multiple', 'text'].some(function (type) {
|
||||
return type === _this.passedElement.type;
|
||||
});
|
||||
|
||||
if (canInit) {
|
||||
// If element has already been initalised with Choices
|
||||
if (this.passedElement.getAttribute('data-choice') === 'active') return;
|
||||
|
||||
if (isValidElement && isValidType) {
|
||||
// Let's go
|
||||
this.init();
|
||||
} else {
|
||||
|
@ -247,31 +248,31 @@
|
|||
value: function init() {
|
||||
var callback = arguments.length <= 0 || arguments[0] === undefined ? this.config.callbackOnInit : arguments[0];
|
||||
|
||||
if (this.initialised !== true) {
|
||||
// Set initialise flag
|
||||
this.initialised = true;
|
||||
if (this.initialised === true) return;
|
||||
|
||||
// Create required elements
|
||||
this._createTemplates();
|
||||
// Set initialise flag
|
||||
this.initialised = true;
|
||||
|
||||
// Generate input markup
|
||||
this._createInput();
|
||||
// Create required elements
|
||||
this._createTemplates();
|
||||
|
||||
this.store.subscribe(this.render);
|
||||
// Generate input markup
|
||||
this._createInput();
|
||||
|
||||
// Render any items
|
||||
this.render();
|
||||
this.store.subscribe(this.render);
|
||||
|
||||
// Trigger event listeners
|
||||
this._addEventListeners();
|
||||
// Render any items
|
||||
this.render();
|
||||
|
||||
// Run callback if it is a function
|
||||
if (callback) {
|
||||
if ((0, _utils.isType)('Function', callback)) {
|
||||
callback();
|
||||
} else {
|
||||
console.error('callbackOnInit: Callback is not a function');
|
||||
}
|
||||
// Trigger event listeners
|
||||
this._addEventListeners();
|
||||
|
||||
// Run callback if it is a function
|
||||
if (callback) {
|
||||
if ((0, _utils.isType)('Function', callback)) {
|
||||
callback();
|
||||
} else {
|
||||
console.error('callbackOnInit: Callback is not a function');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,6 +286,8 @@
|
|||
}, {
|
||||
key: 'destroy',
|
||||
value: function destroy() {
|
||||
if (this.initialised !== true) return;
|
||||
|
||||
this._removeEventListeners();
|
||||
|
||||
this.passedElement.classList.remove(this.config.classNames.input, this.config.classNames.hiddenState);
|
||||
|
@ -600,29 +603,29 @@
|
|||
value: function setValue(args) {
|
||||
var _this8 = this;
|
||||
|
||||
if (this.initialised === true) {
|
||||
// Convert args to an itterable array
|
||||
var values = [].concat(_toConsumableArray(args));
|
||||
if (this.initialised !== true) return;
|
||||
|
||||
values.forEach(function (item) {
|
||||
if ((0, _utils.isType)('Object', item)) {
|
||||
if (!item.value) return;
|
||||
// If we are dealing with a select input, we need to create an option first
|
||||
// that is then selected. For text inputs we can just add items normally.
|
||||
if (_this8.passedElement.type !== 'text') {
|
||||
_this8._addChoice(true, false, item.value, item.label, -1);
|
||||
} else {
|
||||
_this8._addItem(item.value, item.label, item.id);
|
||||
}
|
||||
} else if ((0, _utils.isType)('String', item)) {
|
||||
if (_this8.passedElement.type !== 'text') {
|
||||
_this8._addChoice(true, false, item, item, -1);
|
||||
} else {
|
||||
_this8._addItem(item);
|
||||
}
|
||||
// Convert args to an itterable array
|
||||
var values = [].concat(_toConsumableArray(args));
|
||||
|
||||
values.forEach(function (item) {
|
||||
if ((0, _utils.isType)('Object', item)) {
|
||||
if (!item.value) return;
|
||||
// If we are dealing with a select input, we need to create an option first
|
||||
// that is then selected. For text inputs we can just add items normally.
|
||||
if (_this8.passedElement.type !== 'text') {
|
||||
_this8._addChoice(true, false, item.value, item.label, -1);
|
||||
} else {
|
||||
_this8._addItem(item.value, item.label, item.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if ((0, _utils.isType)('String', item)) {
|
||||
if (_this8.passedElement.type !== 'text') {
|
||||
_this8._addChoice(true, false, item, item, -1);
|
||||
} else {
|
||||
_this8._addItem(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -639,31 +642,29 @@
|
|||
value: function setValueByChoice(value) {
|
||||
var _this9 = this;
|
||||
|
||||
if (this.passedElement.type !== 'text') {
|
||||
(function () {
|
||||
var choices = _this9.store.getChoices();
|
||||
// If only one value has been passed, convert to array
|
||||
var choiceValue = (0, _utils.isType)('Array', value) ? value : [value];
|
||||
if (this.passedElement.type === 'text') return;
|
||||
|
||||
// Loop through each value and
|
||||
choiceValue.forEach(function (val) {
|
||||
var foundChoice = choices.find(function (choice) {
|
||||
// Check 'value' property exists and the choice isn't already selected
|
||||
return choice.value === val;
|
||||
});
|
||||
var choices = this.store.getChoices();
|
||||
// If only one value has been passed, convert to array
|
||||
var choiceValue = (0, _utils.isType)('Array', value) ? value : [value];
|
||||
|
||||
if (foundChoice) {
|
||||
if (!foundChoice.selected) {
|
||||
_this9._addItem(foundChoice.value, foundChoice.label, foundChoice.id);
|
||||
} else {
|
||||
console.warn('Attempting to select choice already selected');
|
||||
}
|
||||
} else {
|
||||
console.warn('Attempting to select choice that does not exist');
|
||||
}
|
||||
});
|
||||
})();
|
||||
}
|
||||
// Loop through each value and
|
||||
choiceValue.forEach(function (val) {
|
||||
var foundChoice = choices.find(function (choice) {
|
||||
// Check 'value' property exists and the choice isn't already selected
|
||||
return choice.value === val;
|
||||
});
|
||||
|
||||
if (foundChoice) {
|
||||
if (!foundChoice.selected) {
|
||||
_this9._addItem(foundChoice.value, foundChoice.label, foundChoice.id);
|
||||
} else {
|
||||
console.warn('Attempting to select choice already selected');
|
||||
}
|
||||
} else {
|
||||
console.warn('Attempting to select choice that does not exist');
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -681,20 +682,20 @@
|
|||
value: function setChoices(choices, value, label) {
|
||||
var _this10 = this;
|
||||
|
||||
if (this.initialised === true) {
|
||||
if (this.passedElement.type === 'select-one' || this.passedElement.type === 'select-multiple') {
|
||||
if (!(0, _utils.isType)('Array', choices) || !value) return;
|
||||
if (this.initialised !== true) return;
|
||||
|
||||
if (choices && choices.length) {
|
||||
this.containerOuter.classList.remove(this.config.classNames.loadingState);
|
||||
choices.forEach(function (result, index) {
|
||||
if (result.choices) {
|
||||
_this10._addGroup(result, index);
|
||||
} else {
|
||||
_this10._addChoice(result.selected ? result.selected : false, result.disabled ? result.disabled : false, result[value], result[label]);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.passedElement.type === 'select-one' || this.passedElement.type === 'select-multiple') {
|
||||
if (!(0, _utils.isType)('Array', choices) || !value) return;
|
||||
|
||||
if (choices && choices.length) {
|
||||
this.containerOuter.classList.remove(this.config.classNames.loadingState);
|
||||
choices.forEach(function (result, index) {
|
||||
if (result.choices) {
|
||||
_this10._addGroup(result, index);
|
||||
} else {
|
||||
_this10._addChoice(result.selected ? result.selected : false, result.disabled ? result.disabled : false, result[value], result[label]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return this;
|
||||
|
@ -785,43 +786,40 @@
|
|||
value: function ajax(fn) {
|
||||
var _this11 = this;
|
||||
|
||||
if (this.initialised === true) {
|
||||
if (this.passedElement.type === 'select-one' || this.passedElement.type === 'select-multiple') {
|
||||
this.containerOuter.classList.add(this.config.classNames.loadingState);
|
||||
this.containerOuter.setAttribute('aria-busy', 'true');
|
||||
if (this.passedElement.type === 'select-one') {
|
||||
var placeholderItem = this._getTemplate('placeholder', this.config.loadingText);
|
||||
this.itemList.appendChild(placeholderItem);
|
||||
} else {
|
||||
this.input.placeholder = this.config.loadingText;
|
||||
}
|
||||
if (this.initialised !== true) return;
|
||||
|
||||
var callback = function callback(results, value, label) {
|
||||
if (!(0, _utils.isType)('Array', results) || !value) return;
|
||||
if (results && results.length) {
|
||||
// Remove loading states/text
|
||||
_this11.containerOuter.classList.remove(_this11.config.classNames.loadingState);
|
||||
if (_this11.passedElement.type === 'select-multiple') {
|
||||
var placeholder = _this11.config.placeholder ? _this11.config.placeholderValue || _this11.passedElement.getAttribute('placeholder') : false;
|
||||
if (placeholder) {
|
||||
_this11.input.placeholder = placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
// Add each result as a choice
|
||||
results.forEach(function (result, index) {
|
||||
// Select first choice in list if single select input
|
||||
if (index === 0 && _this11.passedElement.type === 'select-one') {
|
||||
_this11._addChoice(true, false, result[value], result[label]);
|
||||
} else {
|
||||
_this11._addChoice(false, false, result[value], result[label]);
|
||||
}
|
||||
});
|
||||
}
|
||||
_this11.containerOuter.removeAttribute('aria-busy');
|
||||
};
|
||||
fn(callback);
|
||||
if (this.passedElement.type === 'select-one' || this.passedElement.type === 'select-multiple') {
|
||||
this.containerOuter.classList.add(this.config.classNames.loadingState);
|
||||
this.containerOuter.setAttribute('aria-busy', 'true');
|
||||
if (this.passedElement.type === 'select-one') {
|
||||
var placeholderItem = this._getTemplate('placeholder', this.config.loadingText);
|
||||
this.itemList.appendChild(placeholderItem);
|
||||
} else {
|
||||
this.input.placeholder = this.config.loadingText;
|
||||
}
|
||||
|
||||
var callback = function callback(results, value, label) {
|
||||
if (!(0, _utils.isType)('Array', results) || !value) return;
|
||||
if (results && results.length) {
|
||||
// Remove loading states/text
|
||||
_this11.containerOuter.classList.remove(_this11.config.classNames.loadingState);
|
||||
|
||||
if (_this11.passedElement.type === 'select-multiple') {
|
||||
var placeholder = _this11.config.placeholder ? _this11.config.placeholderValue || _this11.passedElement.getAttribute('placeholder') : false;
|
||||
if (placeholder) {
|
||||
_this11.input.placeholder = placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
// Add each result as a choice
|
||||
results.forEach(function (result, index) {
|
||||
_this11._addChoice(false, false, result[value], result[label]);
|
||||
});
|
||||
}
|
||||
_this11.containerOuter.removeAttribute('aria-busy');
|
||||
};
|
||||
|
||||
fn(callback);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -1064,6 +1062,7 @@
|
|||
var _this14 = this;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
if (this.input === document.activeElement) {
|
||||
var choices = this.store.getChoices();
|
||||
var hasUnactiveChoices = choices.some(function (option) {
|
||||
|
@ -1086,7 +1085,6 @@
|
|||
include: 'score'
|
||||
});
|
||||
var results = fuse.search(needle);
|
||||
|
||||
_this14.currentValue = newValue;
|
||||
_this14.highlightPosition = 0;
|
||||
_this14.isSearching = true;
|
||||
|
@ -2157,6 +2155,7 @@
|
|||
|
||||
// Join choices with preset choices and add them
|
||||
allChoices.concat(_this19.presetChoices).forEach(function (o, index) {
|
||||
// Pre-select first choice if it's a single select
|
||||
if (index === 0 && _this19.passedElement.type === 'select-one') {
|
||||
_this19._addChoice(true, o.disabled ? o.disabled : false, o.value, o.label);
|
||||
} else {
|
||||
|
@ -2195,7 +2194,12 @@
|
|||
var groupFragment = fragment || document.createDocumentFragment();
|
||||
var filter = this.config.sortFilter;
|
||||
|
||||
groups.sort(filter).forEach(function (group) {
|
||||
// If sorting is enabled, filter groups
|
||||
if (this.config.shouldSort) {
|
||||
groups.sort(filter);
|
||||
}
|
||||
|
||||
groups.forEach(function (group) {
|
||||
// Grab options that are children of this group
|
||||
var groupChoices = choices.filter(function (choice) {
|
||||
if (_this20.passedElement.type === 'select-one') {
|
||||
|
@ -2233,11 +2237,15 @@
|
|||
var choicesFragment = fragment || document.createDocumentFragment();
|
||||
var filter = this.isSearching ? _utils.sortByScore : this.config.sortFilter;
|
||||
|
||||
choices.sort(filter).forEach(function (choice) {
|
||||
// If sorting is enabled or the user is searching, filter choices
|
||||
if (this.config.shouldSort || this.isSearching) {
|
||||
choices.sort(filter);
|
||||
}
|
||||
|
||||
choices.forEach(function (choice) {
|
||||
var dropdownItem = _this21._getTemplate('choice', choice);
|
||||
if (_this21.passedElement.type === 'select-one') {
|
||||
choicesFragment.appendChild(dropdownItem);
|
||||
} else if (!choice.selected) {
|
||||
var shouldRender = _this21.passedElement.type === 'select-one' || !choice.selected;
|
||||
if (shouldRender) {
|
||||
choicesFragment.appendChild(dropdownItem);
|
||||
}
|
||||
});
|
||||
|
|
2
assets/scripts/dist/choices.js.map
vendored
2
assets/scripts/dist/choices.js.map
vendored
File diff suppressed because one or more lines are too long
4
assets/scripts/dist/choices.min.js
vendored
4
assets/scripts/dist/choices.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -42,6 +42,12 @@ export default class Choices {
|
|||
}
|
||||
}
|
||||
|
||||
// Retrieve triggering element (i.e. element with 'data-choice' trigger)
|
||||
this.passedElement = isType('String', element) ? document.querySelector(element) : element;
|
||||
|
||||
// If element has already been initalised with Choices, return it silently
|
||||
if (this.passedElement.getAttribute('data-choice') === 'active') return;
|
||||
|
||||
const defaultConfig = {
|
||||
items: [],
|
||||
choices: [],
|
||||
|
@ -111,12 +117,14 @@ export default class Choices {
|
|||
this.currentState = {};
|
||||
this.prevState = {};
|
||||
this.currentValue = '';
|
||||
|
||||
// Retrieve triggering element (i.e. element with 'data-choice' trigger)
|
||||
this.passedElement = isType('String', element) ? document.querySelector(element) : element;
|
||||
|
||||
this.highlightPosition = 0;
|
||||
|
||||
// Track searching
|
||||
this.canSearch = this.config.search;
|
||||
// Track tapping
|
||||
this.wasTap = true;
|
||||
// Focus containerOuter but not show dropdown if true
|
||||
this.focusAndHideDropdown = false;
|
||||
|
||||
// Assing preset choices from passed object
|
||||
this.presetChoices = this.config.choices;
|
||||
|
@ -148,23 +156,15 @@ export default class Choices {
|
|||
this._onPaste = this._onPaste.bind(this);
|
||||
this._onInput = this._onInput.bind(this);
|
||||
|
||||
// Focus containerOuter but not show dropdown if true
|
||||
this.focusAndHideDropdown = false;
|
||||
|
||||
// Monitor touch taps/scrolls
|
||||
this.wasTap = true;
|
||||
|
||||
// Cutting the mustard
|
||||
const cuttingTheMustard = 'querySelector' in document && 'addEventListener' in document && 'classList' in document.createElement('div');
|
||||
if (!cuttingTheMustard) console.error('Choices: Your browser doesn\'t support Choices');
|
||||
|
||||
// Input type check
|
||||
const canInit = this.passedElement && isElement(this.passedElement) && ['select-one', 'select-multiple', 'text'].some(type => type === this.passedElement.type);
|
||||
|
||||
if (canInit) {
|
||||
// If element has already been initalised with Choices
|
||||
if (this.passedElement.getAttribute('data-choice') === 'active') return;
|
||||
const isValidElement = this.passedElement && isElement(this.passedElement);
|
||||
const isValidType = ['select-one', 'select-multiple', 'text'].some(type => type === this.passedElement.type);
|
||||
|
||||
if (isValidElement && isValidType) {
|
||||
// Let's go
|
||||
this.init();
|
||||
} else {
|
||||
|
@ -178,31 +178,31 @@ export default class Choices {
|
|||
* @public
|
||||
*/
|
||||
init(callback = this.config.callbackOnInit) {
|
||||
if (this.initialised !== true) {
|
||||
// Set initialise flag
|
||||
this.initialised = true;
|
||||
if (this.initialised === true) return;
|
||||
|
||||
// Create required elements
|
||||
this._createTemplates();
|
||||
// Set initialise flag
|
||||
this.initialised = true;
|
||||
|
||||
// Generate input markup
|
||||
this._createInput();
|
||||
// Create required elements
|
||||
this._createTemplates();
|
||||
|
||||
this.store.subscribe(this.render);
|
||||
// Generate input markup
|
||||
this._createInput();
|
||||
|
||||
// Render any items
|
||||
this.render();
|
||||
this.store.subscribe(this.render);
|
||||
|
||||
// Trigger event listeners
|
||||
this._addEventListeners();
|
||||
// Render any items
|
||||
this.render();
|
||||
|
||||
// Run callback if it is a function
|
||||
if (callback) {
|
||||
if (isType('Function', callback)) {
|
||||
callback();
|
||||
} else {
|
||||
console.error('callbackOnInit: Callback is not a function');
|
||||
}
|
||||
// Trigger event listeners
|
||||
this._addEventListeners();
|
||||
|
||||
// Run callback if it is a function
|
||||
if (callback) {
|
||||
if (isType('Function', callback)) {
|
||||
callback();
|
||||
} else {
|
||||
console.error('callbackOnInit: Callback is not a function');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,6 +213,8 @@ export default class Choices {
|
|||
* @public
|
||||
*/
|
||||
destroy() {
|
||||
if (this.initialised !== true) return;
|
||||
|
||||
this._removeEventListeners();
|
||||
|
||||
this.passedElement.classList.remove(this.config.classNames.input, this.config.classNames.hiddenState);
|
||||
|
@ -472,29 +474,29 @@ export default class Choices {
|
|||
* @public
|
||||
*/
|
||||
setValue(args) {
|
||||
if (this.initialised === true) {
|
||||
// Convert args to an itterable array
|
||||
const values = [...args];
|
||||
if (this.initialised !== true) return;
|
||||
|
||||
values.forEach((item) => {
|
||||
if (isType('Object', item)) {
|
||||
if (!item.value) return;
|
||||
// If we are dealing with a select input, we need to create an option first
|
||||
// that is then selected. For text inputs we can just add items normally.
|
||||
if (this.passedElement.type !== 'text') {
|
||||
this._addChoice(true, false, item.value, item.label, -1);
|
||||
} else {
|
||||
this._addItem(item.value, item.label, item.id);
|
||||
}
|
||||
} else if (isType('String', item)) {
|
||||
if (this.passedElement.type !== 'text') {
|
||||
this._addChoice(true, false, item, item, -1);
|
||||
} else {
|
||||
this._addItem(item);
|
||||
}
|
||||
// Convert args to an itterable array
|
||||
const values = [...args];
|
||||
|
||||
values.forEach((item) => {
|
||||
if (isType('Object', item)) {
|
||||
if (!item.value) return;
|
||||
// If we are dealing with a select input, we need to create an option first
|
||||
// that is then selected. For text inputs we can just add items normally.
|
||||
if (this.passedElement.type !== 'text') {
|
||||
this._addChoice(true, false, item.value, item.label, -1);
|
||||
} else {
|
||||
this._addItem(item.value, item.label, item.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (isType('String', item)) {
|
||||
if (this.passedElement.type !== 'text') {
|
||||
this._addChoice(true, false, item, item, -1);
|
||||
} else {
|
||||
this._addItem(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -506,29 +508,29 @@ export default class Choices {
|
|||
* @public
|
||||
*/
|
||||
setValueByChoice(value) {
|
||||
if (this.passedElement.type !== 'text') {
|
||||
const choices = this.store.getChoices();
|
||||
// If only one value has been passed, convert to array
|
||||
const choiceValue = isType('Array', value) ? value : [value];
|
||||
if (this.passedElement.type === 'text') return;
|
||||
|
||||
// Loop through each value and
|
||||
choiceValue.forEach((val) => {
|
||||
const foundChoice = choices.find((choice) => {
|
||||
// Check 'value' property exists and the choice isn't already selected
|
||||
return choice.value === val;
|
||||
});
|
||||
const choices = this.store.getChoices();
|
||||
// If only one value has been passed, convert to array
|
||||
const choiceValue = isType('Array', value) ? value : [value];
|
||||
|
||||
if (foundChoice) {
|
||||
if (!foundChoice.selected) {
|
||||
this._addItem(foundChoice.value, foundChoice.label, foundChoice.id);
|
||||
} else {
|
||||
console.warn('Attempting to select choice already selected');
|
||||
}
|
||||
} else {
|
||||
console.warn('Attempting to select choice that does not exist');
|
||||
}
|
||||
// Loop through each value and
|
||||
choiceValue.forEach((val) => {
|
||||
const foundChoice = choices.find((choice) => {
|
||||
// Check 'value' property exists and the choice isn't already selected
|
||||
return choice.value === val;
|
||||
});
|
||||
}
|
||||
|
||||
if (foundChoice) {
|
||||
if (!foundChoice.selected) {
|
||||
this._addItem(foundChoice.value, foundChoice.label, foundChoice.id);
|
||||
} else {
|
||||
console.warn('Attempting to select choice already selected');
|
||||
}
|
||||
} else {
|
||||
console.warn('Attempting to select choice that does not exist');
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -541,20 +543,20 @@ export default class Choices {
|
|||
* @public
|
||||
*/
|
||||
setChoices(choices, value, label) {
|
||||
if (this.initialised === true) {
|
||||
if (this.passedElement.type === 'select-one' || this.passedElement.type === 'select-multiple') {
|
||||
if (!isType('Array', choices) || !value) return;
|
||||
if (this.initialised !== true) return;
|
||||
|
||||
if (choices && choices.length) {
|
||||
this.containerOuter.classList.remove(this.config.classNames.loadingState);
|
||||
choices.forEach((result, index) => {
|
||||
if (result.choices) {
|
||||
this._addGroup(result, index);
|
||||
} else {
|
||||
this._addChoice(result.selected ? result.selected : false, result.disabled ? result.disabled : false, result[value], result[label]);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.passedElement.type === 'select-one' || this.passedElement.type === 'select-multiple') {
|
||||
if (!isType('Array', choices) || !value) return;
|
||||
|
||||
if (choices && choices.length) {
|
||||
this.containerOuter.classList.remove(this.config.classNames.loadingState);
|
||||
choices.forEach((result, index) => {
|
||||
if (result.choices) {
|
||||
this._addGroup(result, index);
|
||||
} else {
|
||||
this._addChoice(result.selected ? result.selected : false, result.disabled ? result.disabled : false, result[value], result[label]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return this;
|
||||
|
@ -628,43 +630,40 @@ export default class Choices {
|
|||
* @public
|
||||
*/
|
||||
ajax(fn) {
|
||||
if (this.initialised === true) {
|
||||
if (this.passedElement.type === 'select-one' || this.passedElement.type === 'select-multiple') {
|
||||
this.containerOuter.classList.add(this.config.classNames.loadingState);
|
||||
this.containerOuter.setAttribute('aria-busy', 'true');
|
||||
if (this.passedElement.type === 'select-one') {
|
||||
const placeholderItem = this._getTemplate('placeholder', this.config.loadingText);
|
||||
this.itemList.appendChild(placeholderItem);
|
||||
} else {
|
||||
this.input.placeholder = this.config.loadingText;
|
||||
}
|
||||
if (this.initialised !== true) return;
|
||||
|
||||
const callback = (results, value, label) => {
|
||||
if (!isType('Array', results) || !value) return;
|
||||
if (results && results.length) {
|
||||
// Remove loading states/text
|
||||
this.containerOuter.classList.remove(this.config.classNames.loadingState);
|
||||
if (this.passedElement.type === 'select-multiple') {
|
||||
const placeholder = this.config.placeholder ? this.config.placeholderValue || this.passedElement.getAttribute('placeholder') : false;
|
||||
if (placeholder) {
|
||||
this.input.placeholder = placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
// Add each result as a choice
|
||||
results.forEach((result, index) => {
|
||||
// Select first choice in list if single select input
|
||||
if (index === 0 && this.passedElement.type === 'select-one') {
|
||||
this._addChoice(true, false, result[value], result[label]);
|
||||
} else {
|
||||
this._addChoice(false, false, result[value], result[label]);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.containerOuter.removeAttribute('aria-busy');
|
||||
};
|
||||
fn(callback);
|
||||
if (this.passedElement.type === 'select-one' || this.passedElement.type === 'select-multiple') {
|
||||
this.containerOuter.classList.add(this.config.classNames.loadingState);
|
||||
this.containerOuter.setAttribute('aria-busy', 'true');
|
||||
if (this.passedElement.type === 'select-one') {
|
||||
const placeholderItem = this._getTemplate('placeholder', this.config.loadingText);
|
||||
this.itemList.appendChild(placeholderItem);
|
||||
} else {
|
||||
this.input.placeholder = this.config.loadingText;
|
||||
}
|
||||
|
||||
const callback = (results, value, label) => {
|
||||
if (!isType('Array', results) || !value) return;
|
||||
if (results && results.length) {
|
||||
// Remove loading states/text
|
||||
this.containerOuter.classList.remove(this.config.classNames.loadingState);
|
||||
|
||||
if (this.passedElement.type === 'select-multiple') {
|
||||
const placeholder = this.config.placeholder ? this.config.placeholderValue || this.passedElement.getAttribute('placeholder') : false;
|
||||
if (placeholder) {
|
||||
this.input.placeholder = placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
// Add each result as a choice
|
||||
results.forEach((result, index) => {
|
||||
this._addChoice(false, false, result[value], result[label]);
|
||||
});
|
||||
}
|
||||
this.containerOuter.removeAttribute('aria-busy');
|
||||
};
|
||||
|
||||
fn(callback);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -867,6 +866,7 @@ export default class Choices {
|
|||
*/
|
||||
_searchChoices(value) {
|
||||
if (!value) return;
|
||||
|
||||
if (this.input === document.activeElement) {
|
||||
const choices = this.store.getChoices();
|
||||
const hasUnactiveChoices = choices.some((option) => option.active !== true);
|
||||
|
@ -1880,7 +1880,6 @@ export default class Choices {
|
|||
const passedOptions = Array.from(this.passedElement.options);
|
||||
const allChoices = [];
|
||||
|
||||
|
||||
// Create array of options from option elements
|
||||
passedOptions.forEach((o) => {
|
||||
allChoices.push({
|
||||
|
@ -1895,6 +1894,7 @@ export default class Choices {
|
|||
allChoices
|
||||
.concat(this.presetChoices)
|
||||
.forEach((o, index) => {
|
||||
// Pre-select first choice if it's a single select
|
||||
if (index === 0 && this.passedElement.type === 'select-one') {
|
||||
this._addChoice(true, o.disabled ? o.disabled : false, o.value, o.label);
|
||||
} else {
|
||||
|
@ -1927,26 +1927,29 @@ export default class Choices {
|
|||
const groupFragment = fragment || document.createDocumentFragment();
|
||||
const filter = this.config.sortFilter;
|
||||
|
||||
groups
|
||||
.sort(filter)
|
||||
.forEach((group) => {
|
||||
// Grab options that are children of this group
|
||||
const groupChoices = choices.filter((choice) => {
|
||||
if (this.passedElement.type === 'select-one') {
|
||||
return choice.groupId === group.id;
|
||||
}
|
||||
// If sorting is enabled, filter groups
|
||||
if (this.config.shouldSort) {
|
||||
groups.sort(filter);
|
||||
}
|
||||
|
||||
return choice.groupId === group.id && !choice.selected;
|
||||
});
|
||||
|
||||
if (groupChoices.length >= 1) {
|
||||
const dropdownGroup = this._getTemplate('choiceGroup', group);
|
||||
groupFragment.appendChild(dropdownGroup);
|
||||
|
||||
this.renderChoices(groupChoices, groupFragment);
|
||||
groups.forEach((group) => {
|
||||
// Grab options that are children of this group
|
||||
const groupChoices = choices.filter((choice) => {
|
||||
if (this.passedElement.type === 'select-one') {
|
||||
return choice.groupId === group.id;
|
||||
}
|
||||
|
||||
return choice.groupId === group.id && !choice.selected;
|
||||
});
|
||||
|
||||
if (groupChoices.length >= 1) {
|
||||
const dropdownGroup = this._getTemplate('choiceGroup', group);
|
||||
groupFragment.appendChild(dropdownGroup);
|
||||
|
||||
this.renderChoices(groupChoices, groupFragment);
|
||||
}
|
||||
});
|
||||
|
||||
return groupFragment;
|
||||
}
|
||||
|
||||
|
@ -1960,20 +1963,20 @@ export default class Choices {
|
|||
renderChoices(choices, fragment) {
|
||||
// Create a fragment to store our list items (so we don't have to update the DOM for each item)
|
||||
const choicesFragment = fragment || document.createDocumentFragment();
|
||||
const filter = this.isSearching ? sortByScore : this.config.sortFilter;
|
||||
|
||||
// If sorting is enabled or the user is searching, filter choices
|
||||
if (this.config.shouldSort || this.isSearching) {
|
||||
const filter = this.isSearching ? sortByScore : this.config.sortFilter;
|
||||
choices.sort(filter);
|
||||
}
|
||||
choices
|
||||
.forEach((choice) => {
|
||||
const dropdownItem = this._getTemplate('choice', choice);
|
||||
if (this.passedElement.type === 'select-one') {
|
||||
choicesFragment.appendChild(dropdownItem);
|
||||
} else if (!choice.selected) {
|
||||
choicesFragment.appendChild(dropdownItem);
|
||||
}
|
||||
});
|
||||
|
||||
choices.forEach((choice) => {
|
||||
const dropdownItem = this._getTemplate('choice', choice);
|
||||
const shouldRender = this.passedElement.type === 'select-one' || !choice.selected;
|
||||
if (shouldRender) {
|
||||
choicesFragment.appendChild(dropdownItem);
|
||||
}
|
||||
});
|
||||
|
||||
return choicesFragment;
|
||||
}
|
||||
|
|
28
index.html
28
index.html
|
@ -41,7 +41,9 @@
|
|||
<h1 class="visible-ie">Choices.js</h1>
|
||||
<p>Choices.js is a lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.</p>
|
||||
<p>For all config options, visit the <a href="https://github.com/jshjohnson/Choices">GitHub repo</a>.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Text inputs</h2>
|
||||
<label for="choices-1">Limited to 5 values with remove button</label>
|
||||
<input class="form-control" id="choices-1" type="text" value="preset-1,preset-2" placeholder="Enter something">
|
||||
|
@ -170,6 +172,28 @@
|
|||
<label for="choices-17">Option selected via config</label>
|
||||
<select class="form-control" name="choices-17" id="choices-17" placeholder="This is a placeholder"></select>
|
||||
|
||||
<label for="choices-18">Options without sorting</label>
|
||||
<select class="form-control" name="choices-18" id="choices-18" placeholder="This is a placeholder">
|
||||
<option value="Madrid">Madrid</option>
|
||||
<option value="Toronto">Toronto</option>
|
||||
<option value="Vancouver">Vancouver</option>
|
||||
<option value="London">London</option>
|
||||
<option value="Manchester">Manchester</option>
|
||||
<option value="Liverpool">Liverpool</option>
|
||||
<option value="Paris">Paris</option>
|
||||
<option value="Malaga">Malaga</option>
|
||||
<option value="Washington" disabled>Washington</option>
|
||||
<option value="Lyon">Lyon</option>
|
||||
<option value="Marseille">Marseille</option>
|
||||
<option value="Hamburg">Hamburg</option>
|
||||
<option value="Munich">Munich</option>
|
||||
<option value="Barcelona">Barcelona</option>
|
||||
<option value="Berlin">Berlin</option>
|
||||
<option value="Montreal">Montreal</option>
|
||||
<option value="New York">New York</option>
|
||||
<option value="Michigan">Michigan</option>
|
||||
</select>
|
||||
|
||||
<p>Below is an example of how you could have two select inputs depend on eachother. 'Boroughs' will only be enabled if the value of 'States' is 'New York'</p>
|
||||
<label for="cities">States</label>
|
||||
<select class="form-control" name="cities" id="cities" placeholder="Choose a state">
|
||||
|
@ -335,6 +359,10 @@
|
|||
],
|
||||
}).setValueByChoice('Two');
|
||||
|
||||
var example16 = new Choices('#choices-18', {
|
||||
shouldSort: false,
|
||||
});
|
||||
|
||||
var cities = new Choices(document.getElementById('cities'), {
|
||||
callbackOnChange: function(value) {
|
||||
if(value === 'New York') {
|
||||
|
|
Loading…
Reference in a new issue