Populate options from ajax api

This commit is contained in:
Josh Johnson 2016-05-08 00:02:52 +01:00
parent 57ad1dc31c
commit ec8c324383
7 changed files with 251 additions and 183 deletions

File diff suppressed because one or more lines are too long

View file

@ -69,10 +69,9 @@ export class Choices {
flippedState: 'is-flipped',
selectedState: 'is-selected'
},
callbackOnInit: function() {},
callbackOnRender: function() {},
callbackOnRemoveItem: function() {},
callbackOnAddItem: function() {}
callbackOnInit: () => {},
callbackOnRemoveItem: () => {},
callbackOnAddItem: () => {}
};
// Merge options with user options
@ -82,6 +81,7 @@ export class Choices {
this.store = new Store(this.render);
// State tracking
this.initialised = false;
this.currentState = {};
this.prevState = {};
@ -102,6 +102,7 @@ export class Choices {
this.init = this.init.bind(this);
this.render = this.render.bind(this);
this.destroy = this.destroy.bind(this);
this.disable = this.disable.bind(this);
// Bind event handlers
this.onFocus = this.onFocus.bind(this);
@ -137,39 +138,35 @@ export class Choices {
handleEnter(activeItems, value) {
let canUpdate = true;
if(this.passedElement.type === 'text') {
if(this.options.addItems) {
if (this.options.maxItems && this.options.maxItems <= this.list.children.length) {
// If there is a max entry limit and we have reached that limit
// don't update
canUpdate = false;
} else if(this.options.allowDuplicates === false && this.passedElement.value) {
// If no duplicates are allowed, and the value already exists
// in the array, don't update
canUpdate = !activeItems.some((item) => {
return item.value === value;
});
}
} else {
if(this.options.addItems) {
if (this.options.maxItems && this.options.maxItems <= this.list.children.length) {
// If there is a max entry limit and we have reached that limit
// don't update
canUpdate = false;
} else if(this.options.allowDuplicates === false && this.passedElement.value) {
// If no duplicates are allowed, and the value already exists
// in the array, don't update
canUpdate = !activeItems.some((item) => item.value === value );
}
} else {
canUpdate = false;
}
if (canUpdate) {
let canAddItem = true;
// If a user has supplied a regular expression filter
if(this.options.regexFilter) {
// Determine whether we can update based on whether
// our regular expression passes
canAddItem = this.regexFilter(value);
}
if (canUpdate) {
let canAddItem = true;
// If a user has supplied a regular expression filter
if(this.options.regexFilter) {
// Determine whether we can update based on whether
// our regular expression passes
canAddItem = this.regexFilter(value);
}
// All is good, add
if(canAddItem) {
this.toggleDropdown();
this.addItem(value);
this.clearInput(this.passedElement);
}
// All is good, add
if(canAddItem) {
this.toggleDropdown();
this.addItem(value);
this.clearInput(this.passedElement);
}
}
};
@ -226,7 +223,7 @@ export class Choices {
// If a user is typing and the dropdown is not active
if(this.passedElement.type !== 'text' && /[a-zA-Z0-9-_ ]/.test(keyString) && !hasActiveDropdown) {
this.toggleDropdown();
this.showDropdown();
}
switch (e.keyCode) {
@ -240,13 +237,17 @@ export class Choices {
break;
case enterKey:
if(this.passedElement.type === 'select-one') {
this.toggleDropdown();
}
// If enter key is pressed and the input has a value
if(e.target.value && this.passedElement.type === 'text') {
const value = this.input.value;
this.handleEnter(activeItems, value);
}
if(this.dropdown && hasActiveDropdown) {
if(hasActiveDropdown) {
const highlighted = this.dropdown.querySelector(`.${this.options.classNames.highlightedState}`);
if(highlighted) {
@ -260,7 +261,7 @@ export class Choices {
break;
case escapeKey:
if(this.dropdown && hasActiveDropdown) {
if(hasActiveDropdown) {
this.toggleDropdown();
}
break;
@ -268,7 +269,7 @@ export class Choices {
case downKey:
case upKey:
// If up or down key is pressed, traverse through options
if(this.dropdown && hasActiveDropdown) {
if(hasActiveDropdown) {
const currentEl = this.dropdown.querySelector(`.${this.options.classNames.highlightedState}`);
const directionInt = e.keyCode === downKey ? 1 : -1;
let nextEl;
@ -321,7 +322,7 @@ export class Choices {
if (this.options.maxItems && this.options.maxItems <= this.list.children.length) {
dropdownItem = this.getTemplate('notice', `Only ${ this.options.maxItems } options can be selected.`);
} else {
dropdownItem = this.getTemplate('notice', `Add "${ this.input.value }"`);
dropdownItem = this.getTemplate('notice', `Add "${ this.input.value }"`);
}
this.dropdown.innerHTML = dropdownItem.outerHTML;
@ -335,16 +336,14 @@ export class Choices {
}
}
if(this.dropdown && this.options.allowSearch) {
if(this.options.allowSearch) {
if(this.input === document.activeElement) {
const options = this.store.getOptions();
const hasUnactiveOptions = options.some((option) => {
return option.active !== true;
});
const hasUnactiveOptions = options.some((option) => option.active !== true);
// Check that have a value to search
if(this.input.value && options.length) {
const handleFilter = debounce(() => {
const handleFilter = () => {
// Ensure value *still* has a value after 500 delay
if(this.input.value && this.input.value.length >= 1) {
const haystack = this.store.getOptionsFiltedBySelectable();
@ -361,7 +360,8 @@ export class Choices {
this.isSearching = true;
this.store.dispatch(filterOptions(results));
}
}, 500);
};
handleFilter();
} else if(hasUnactiveOptions) {
// Otherwise reset options to active
@ -414,9 +414,7 @@ export class Choices {
// If we are clicking on an option
const options = this.store.getOptionsFilteredByActive();
const id = e.target.getAttribute('data-id');
const option = options.find((option) => {
return option.id === parseInt(id);
});
const option = options.find((option) => option.id === parseInt(id));
if(!option.selected && !option.disabled) {
this.addItem(option.value, option.label, option.id);
@ -428,9 +426,7 @@ export class Choices {
} else {
// Click is outside of our element so close dropdown and de-select items
const hasSelectedItems = activeItems.some((item) => {
return item.selected === true;
});
const hasSelectedItems = activeItems.some((item) => item.selected === true);
if(hasSelectedItems) {
this.deselectAll();
@ -478,8 +474,12 @@ export class Choices {
* @return
*/
onFocus(e) {
if(!this.containerOuter.classList.contains(this.options.classNames.activeState)) {
const hasActiveDropdown = this.dropdown.classList.contains(this.options.classNames.activeState);
if(e.target === this.input && !hasActiveDropdown) {
this.containerOuter.classList.add(this.options.classNames.focusState);
if(this.passedElement.type === 'select-one' || this.passedElement.type === 'select-multiple'){
this.showDropdown();
}
}
}
@ -490,8 +490,10 @@ export class Choices {
*/
onBlur(e) {
const hasActiveDropdown = this.dropdown.classList.contains(this.options.classNames.activeState);
if(!hasActiveDropdown) {
if(e.target === this.input && !hasActiveDropdown) {
this.containerOuter.classList.remove(this.options.classNames.focusState);
} else {
this.hideDropdown();
}
}
@ -510,9 +512,7 @@ export class Choices {
*/
regexFilter(value) {
const expression = new RegExp(this.options.regexFilter, 'i');
const passesTest = expression.test(value);
return passesTest;
return expression.test(value);
}
/**
@ -691,7 +691,7 @@ export class Choices {
// Run callback if it is a function
if(callback){
if(isType('Function', callback)) {
callback(id, value);
callback(id, passedValue, this.passedElement);
} else {
console.error('callbackOnAddItem: Callback is not a function');
}
@ -717,7 +717,7 @@ export class Choices {
// Run callback
if(callback){
if(!isType('Function', callback)) console.error('callbackOnRemoveItem: Callback is not a function'); return;
callback(value);
callback(id, value, this.passedElement);
}
}
@ -769,6 +769,47 @@ export class Choices {
});
}
/**
* Add option to dropdown
* @param {Object} option Option to add
* @param {Number} groupId ID of the options group
* @return
*/
addOption(option, value, label, groupId = -1) {
// Generate unique id
const options = this.store.getOptions();
const id = options.length + 1;
const isDisabled = option && (option.disabled || option.parentNode.disabled);
this.store.dispatch(addOption(value, label, id, groupId, isDisabled));
if(option && option.selected && !isDisabled) {
this.addItem(value, label, id);
}
}
/**
* Add group to dropdown
* @param {Object} group Group to add
* @param {Number} index Whether this is the first group to add
*/
addGroup(group, id, isFirst) {
const groupOptions = Array.from(group.getElementsByTagName('OPTION'));
const groupId = id;
if(groupOptions) {
this.store.dispatch(addGroup(group.label, groupId, true, group.disabled));
groupOptions.forEach((option, optionIndex) => {
// We want to pre-highlight the first option
const highlighted = isFirst && optionIndex === 0 ? true : false;
this.addOption(option, option.value, option.innerHTML, groupId);
});
} else {
this.store.dispatch(addGroup(group.label, group.id, false, group.disabled));
}
}
/**
* Show dropdown to user by adding active state class
* @return
@ -818,49 +859,37 @@ export class Choices {
}
}
/**
* Add option to dropdown
* @param {Object} option Option to add
* @param {Number} groupId ID of the options group
* @return
/**
* Disable
* @return {[type]} [description]
*/
addOption(option, groupId = -1) {
// Generate unique id
const options = this.store.getOptions();
const id = options.length + 1;
const value = option.value;
const label = option.innerHTML;
const isDisabled = option.disabled || option.parentNode.disabled;
this.store.dispatch(addOption(value, label, id, groupId, isDisabled));
if(option.selected && !isDisabled) {
this.addItem(value, label, id);
disable() {
this.passedElement.disabled = true;
if(this.initialised) {
this.input.disabled = true;
this.containerOuter.classList.add(this.options.classNames.disabledState);
}
}
ajax(fn) {
const callback = (results, title, label) => {
if(results && results.length) {
results.forEach((result) => {
// Add each result to option dropdown
this.addOption(null, result[title], result[label]);
});
}
};
fn(callback);
}
/**
* Add group to dropdown
* @param {Object} group Group to add
* @param {Number} index Whether this is the first group to add
* Get template from name
* @param {String} template Name of template to get
* @param {...} args Data to pass to template
* @return {HTMLElement} Template
*/
addGroup(group, id, isFirst) {
const groupOptions = Array.from(group.getElementsByTagName('OPTION'));
const groupId = id;
if(groupOptions) {
this.store.dispatch(addGroup(group.label, groupId, true, group.disabled));
groupOptions.forEach((option, optionIndex) => {
// We want to pre-highlight the first option
const highlighted = isFirst && optionIndex === 0 ? true : false;
this.addOption(option, groupId);
});
} else {
this.store.dispatch(addGroup(group.label, group.id, false, group.disabled));
}
}
getTemplate(template, ...args) {
if(!template) return;
const templates = this.options.templates;
@ -869,9 +898,7 @@ export class Choices {
/**
* Create HTML element based on type and arguments
* @param {String} template Template to create
* @param {...} args Data
* @return {HTMLElement}
* @return
*/
createTemplates() {
const classNames = this.options.classNames;
@ -931,11 +958,18 @@ export class Choices {
const input = this.getTemplate('input');
const dropdown = this.getTemplate('dropdown');
this.containerOuter = containerOuter;
this.containerInner = containerInner;
this.input = input;
this.list = list;
this.dropdown = dropdown;
// Hide passed input
this.passedElement.classList.add(this.options.classNames.input, this.options.classNames.hiddenState);
this.passedElement.tabIndex = '-1';
this.passedElement.setAttribute('style', 'display:none;');
this.passedElement.setAttribute('aria-hidden', 'true');
this.passedElement.removeAttribute('data-choice');
// Wrap input in container preserving DOM ordering
wrap(this.passedElement, containerInner);
@ -944,14 +978,13 @@ export class Choices {
wrap(containerInner, containerOuter);
// If placeholder has been enabled and we have a value
if (this.options.placeholder && this.options.placeholderValue && this.passedElement.type !== 'select-one') {
if (this.options.placeholder && this.options.placeholderValue) {
input.placeholder = this.options.placeholderValue;
input.style.width = getWidthOfInput(input);
}
if(!this.options.addItems) {
input.disabled = true;
containerOuter.classList.add(this.options.classNames.disabledState);
this.disable();
}
containerOuter.appendChild(containerInner);
@ -974,24 +1007,16 @@ export class Choices {
} else {
const passedOptions = Array.from(this.passedElement.options);
passedOptions.forEach((option) => {
this.addOption(option);
this.addOption(option, option.value, option.innerHTML);
});
}
} else if(this.passedElement.type === 'select-one') {
console.log('select element');
} else if(this.passedElement.type === 'text') {
// Add any preset values seperated by delimiter
this.presetItems.forEach((value) => {
this.addItem(value);
});
}
this.containerOuter = containerOuter;
this.containerInner = containerInner;
this.input = input;
this.list = list;
this.dropdown = dropdown;
}
renderGroups(groups, options, fragment) {
@ -1006,7 +1031,11 @@ export class Choices {
groupOptions.forEach((option, j) => {
const dropdownItem = this.getTemplate('option', option);
dropdownGroup.appendChild(dropdownItem);
if(this.passedElement.type === 'select-one') {
dropdownGroup.appendChild(dropdownItem);
} else if(!option.selected) {
dropdownGroup.appendChild(dropdownItem);
}
});
fragment.appendChild(dropdownGroup);
@ -1027,7 +1056,7 @@ export class Choices {
renderItems(items, fragment) {
// Simplify store data to just values
const itemsFiltered = this.store.getItemsReducedToValues();
const itemsFiltered = this.store.getItemsReducedToValues(items);
// Assign hidden input array of values
this.passedElement.value = itemsFiltered.join(this.options.delimiter);
@ -1143,6 +1172,8 @@ export class Choices {
* @return
*/
init(callback = this.options.callbackOnInit) {
this.initialised = true;
// Create required elements
this.createTemplates();
@ -1176,6 +1207,7 @@ export class Choices {
this.passedElement.tabIndex = '';
this.passedElement.removeAttribute('style', 'display:none;');
this.passedElement.removeAttribute('aria-hidden');
this.passedElement.addAttribute('data-choice');
this.containerOuter.outerHTML = this.passedElement.outerHTML;

View file

@ -65,9 +65,7 @@ export class Store {
* Get items from store reduced to just their values
* @return {Array} Item objects
*/
getItemsReducedToValues() {
const items = this.getItems();
getItemsReducedToValues(items = this.getItems()) {
const values = items.reduce((prev, current) => {
prev.push(current.value);
return prev;

View file

@ -40,6 +40,31 @@ h1, h2, h3, h4, h5, h6 {
.choices {
margin-bottom: 2.4rem;
position: relative; }
.choices.is-disabled .choices__inner, .choices.is-disabled .choices__input {
background-color: #eaeaea;
cursor: not-allowed;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
.choices.is-disabled .choices__item {
cursor: not-allowed; }
.choices[data-type*="select-one"].is-open:after {
border-color: transparent transparent #b7b7b7 transparent;
margin-top: -7.5px; }
.choices[data-type*="select-one"]:after {
content: "";
height: 0;
width: 0;
border-style: solid;
border-color: #b7b7b7 transparent transparent transparent;
border-width: 5px;
position: absolute;
right: 1.15rem;
top: 50%;
margin-top: -2.5px; }
.choices__inner {
background-color: #f9f9f9;
@ -78,11 +103,14 @@ h1, h2, h3, h4, h5, h6 {
margin-right: .375rem;
margin-bottom: .375rem;
background-color: #00BCD4;
border: 1px solid #00b1c7;
border: 1px solid #00a5bb;
color: #FFFFFF;
word-break: break-all; }
.choices__list--multiple .choices__item.is-selected {
background-color: #00a5bb; }
.is-disabled .choices__list--multiple .choices__item {
background-color: #b7b7b7;
border: 1px solid #aaaaaa; }
.choices__list--dropdown {
display: none;
@ -98,6 +126,8 @@ h1, h2, h3, h4, h5, h6 {
max-height: 300px;
overflow: auto;
will-change: scroll-position; }
.choices__list--dropdown.is-active {
display: block; }
.choices__list--dropdown .choices__item {
padding: 1rem;
font-size: 1.4rem; }
@ -116,8 +146,6 @@ h1, h2, h3, h4, h5, h6 {
opacity: .5; }
.is-open .choices__list--dropdown {
border-color: #b7b7b7; }
.choices__list--dropdown.is-active {
display: block; }
.is-flipped .choices__list--dropdown {
top: auto;
bottom: 100%;

View file

@ -1 +1 @@
*,:after,:before{box-sizing:border-box}body,html{margin:0;height:100%;widows:100%}html{font-size:62.5%}body{background-color:#333;font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:1.6rem;color:#fff}label{display:block;margin-bottom:.8rem;font-size:1.4rem;font-weight:500}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:1.2rem;font-weight:500}.container{display:block;margin:auto;max-width:35em;padding:2.4rem}.section{background-color:#fff;padding:2.4rem;color:#333}.choices{margin-bottom:2.4rem;position:relative}.choices__inner{background-color:#f9f9f9;padding:.75rem .75rem .375rem;border:1px solid #ddd;border-radius:.25rem;font-size:1.4rem;cursor:text;overflow:hidden}.choices__inner:focus{outline:1px solid #00bcd4;outline-offset:-1px}.is-focused .choices__inner{border-color:#b7b7b7}.is-open .choices__inner{border-radius:.25rem .25rem 0 0}.is-flipped.is-open .choices__inner{border-radius:0 0 .25rem .25rem}.choices__list{margin:0;padding-left:0;list-style-type:none}.choices__list--single{display:inline-block;padding:.4rem}.choices__list--multiple{display:inline}.choices__list--multiple .choices__item{display:inline-block;border-radius:2rem;padding:.4rem 1rem;font-size:1.2rem;margin-right:.375rem;margin-bottom:.375rem;background-color:#00bcd4;border:1px solid #00b1c7;color:#fff;word-break:break-all}.choices__list--multiple .choices__item.is-selected{background-color:#00a5bb}.choices__list--dropdown{display:none;z-index:1;position:absolute;width:100%;background-color:#fff;border:1px solid #ddd;top:100%;margin-top:-1px;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;max-height:300px;overflow:auto;will-change:scroll-position}.choices__list--dropdown .choices__item{padding:1rem;font-size:1.4rem}.choices__list--dropdown .choices__item--selectable.is-highlighted:after,.choices__list--dropdown .choices__item.is-selected{opacity:.5}.choices__list--dropdown .choices__item.is-selected:hover{background-color:#fff}.choices__list--dropdown .choices__item--selectable:after{content:"Press to select";font-size:12px;opacity:0;float:right}.choices__list--dropdown .choices__item--selectable.is-highlighted{background-color:#f2f2f2}.is-open .choices__list--dropdown{border-color:#b7b7b7}.choices__list--dropdown.is-active{display:block}.is-flipped .choices__list--dropdown{top:auto;bottom:100%;margin-top:0;margin-bottom:-1px;border-radius:.25rem .25rem 0 0}.choices__item{cursor:default}.choices__item--selectable{cursor:pointer}.choices__item--disabled{cursor:not-allowed;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;opacity:.5}.choices__group .choices__heading{font-weight:600;font-size:1.2rem;padding:1rem;border-bottom:1px solid #eaeaea;color:gray}.choices__input{background-color:#f9f9f9;font-size:1.4rem;padding:0;margin-bottom:.5rem;display:inline-block;vertical-align:baseline;border:0;border-radius:0;max-width:100%;padding:.4rem 0 .4rem .2rem}.choices__input:focus{outline:0}
*,:after,:before{box-sizing:border-box}body,html{margin:0;height:100%;widows:100%}html{font-size:62.5%}body{background-color:#333;font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:1.6rem;color:#fff}label{display:block;margin-bottom:.8rem;font-size:1.4rem;font-weight:500}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:1.2rem;font-weight:500}.container{display:block;margin:auto;max-width:35em;padding:2.4rem}.section{background-color:#fff;padding:2.4rem;color:#333}.choices{margin-bottom:2.4rem;position:relative}.choices.is-disabled .choices__inner,.choices.is-disabled .choices__input{background-color:#eaeaea;cursor:not-allowed;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.choices.is-disabled .choices__item{cursor:not-allowed}.choices[data-type*=select-one].is-open:after{border-color:transparent transparent #b7b7b7 transparent;margin-top:-7.5px}.choices[data-type*=select-one]:after{content:"";height:0;width:0;border-style:solid;border-color:#b7b7b7 transparent transparent transparent;border-width:5px;position:absolute;right:1.15rem;top:50%;margin-top:-2.5px}.choices__inner{background-color:#f9f9f9;padding:.75rem .75rem .375rem;border:1px solid #ddd;border-radius:.25rem;font-size:1.4rem;cursor:text;overflow:hidden}.choices__inner:focus{outline:1px solid #00bcd4;outline-offset:-1px}.is-focused .choices__inner{border-color:#b7b7b7}.is-open .choices__inner{border-radius:.25rem .25rem 0 0}.is-flipped.is-open .choices__inner{border-radius:0 0 .25rem .25rem}.choices__list{margin:0;padding-left:0;list-style-type:none}.choices__list--single{display:inline-block;padding:.4rem}.choices__list--multiple{display:inline}.choices__list--multiple .choices__item{display:inline-block;border-radius:2rem;padding:.4rem 1rem;font-size:1.2rem;margin-right:.375rem;margin-bottom:.375rem;background-color:#00bcd4;border:1px solid #00a5bb;color:#fff;word-break:break-all}.choices__list--multiple .choices__item.is-selected{background-color:#00a5bb}.is-disabled .choices__list--multiple .choices__item{background-color:#b7b7b7;border:1px solid #aaa}.choices__list--dropdown{display:none;z-index:1;position:absolute;width:100%;background-color:#fff;border:1px solid #ddd;top:100%;margin-top:-1px;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;max-height:300px;overflow:auto;will-change:scroll-position}.choices__list--dropdown.is-active{display:block}.choices__list--dropdown .choices__item{padding:1rem;font-size:1.4rem}.choices__list--dropdown .choices__item--selectable.is-highlighted:after,.choices__list--dropdown .choices__item.is-selected{opacity:.5}.choices__list--dropdown .choices__item.is-selected:hover{background-color:#fff}.choices__list--dropdown .choices__item--selectable:after{content:"Press to select";font-size:12px;opacity:0;float:right}.choices__list--dropdown .choices__item--selectable.is-highlighted{background-color:#f2f2f2}.is-open .choices__list--dropdown{border-color:#b7b7b7}.is-flipped .choices__list--dropdown{top:auto;bottom:100%;margin-top:0;margin-bottom:-1px;border-radius:.25rem .25rem 0 0}.choices__item{cursor:default}.choices__item--selectable{cursor:pointer}.choices__item--disabled{cursor:not-allowed;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;opacity:.5}.choices__group .choices__heading{font-weight:600;font-size:1.2rem;padding:1rem;border-bottom:1px solid #eaeaea;color:gray}.choices__input{background-color:#f9f9f9;font-size:1.4rem;padding:0;margin-bottom:.5rem;display:inline-block;vertical-align:baseline;border:0;border-radius:0;max-width:100%;padding:.4rem 0 .4rem .2rem}.choices__input:focus{outline:0}

View file

@ -50,6 +50,33 @@ h1, h2, h3, h4, h5, h6 {
.choices {
margin-bottom: $global-guttering;
position: relative;
&.is-disabled {
.choices__inner, .choices__input {
background-color: lighten(#DDDDDD, 5%);
cursor: not-allowed;
user-select: none;
}
.choices__item { cursor: not-allowed; }
}
}
.choices[data-type*="select-one"] {
&.is-open:after {
border-color: transparent transparent darken(#DDDDDD, 15%) transparent;
margin-top: -7.5px;
}
&:after {
content: "";
height: 0;
width: 0;
border-style: solid;
border-color: darken(#DDDDDD, 15%) transparent transparent transparent;
border-width: 5px;
position: absolute;
right: .75rem + .4rem;
top: 50%;
margin-top: -2.5px;
}
}
.choices__inner {
@ -64,7 +91,6 @@ h1, h2, h3, h4, h5, h6 {
outline: 1px solid #00BCD4;
outline-offset: -1px;
}
.is-focused & { border-color: darken(#DDDDDD, 15%); }
.is-open & { border-radius: .25rem .25rem 0 0; }
.is-flipped.is-open & { border-radius: 0 0 .25rem .25rem; }
@ -76,8 +102,6 @@ h1, h2, h3, h4, h5, h6 {
list-style-type: none;
}
.choices__list--options {}
.choices__list--single {
display: inline-block;
padding: .4rem;
@ -93,10 +117,14 @@ h1, h2, h3, h4, h5, h6 {
margin-right: .375rem;
margin-bottom: .375rem;
background-color: #00BCD4;
border: 1px solid darken(#00BCD4, 2.5%);
border: 1px solid darken(#00BCD4, 5%);
color: #FFFFFF;
word-break: break-all;
&.is-selected { background-color: darken(#00BCD4, 5%); }
.is-disabled & {
background-color: darken(#DDDDDD, 15%);
border: 1px solid darken(#DDDDDD, 20%);
}
}
}
@ -114,6 +142,8 @@ h1, h2, h3, h4, h5, h6 {
max-height: 300px;
overflow: auto;
will-change: scroll-position;
&.is-active { display: block; }
.choices__item {
padding: 1rem;
font-size: 1.4rem;
@ -136,8 +166,6 @@ h1, h2, h3, h4, h5, h6 {
}
.is-open & { border-color: darken(#DDDDDD, 15%); }
&.is-active { display: block; }
.is-flipped & {
top: auto;
bottom: 100%;

View file

@ -11,47 +11,35 @@
<div class="container">
<div class="section">
<h1>Choices</h1>
<label for="choices-1">Text input with no values and a limit of 5 items</label>
<h2>Text inputs</h2>
<label for="choices-1">Limited to 5</label>
<input id="choices-1" type="text" value="preset-1 preset-2">
<label for="choices-2">Text input with preset values, custom classes and a placeholder. No duplicate values allowed</label>
<label for="choices-2">Unique values only</label>
<input id="choices-2" type="text" value="preset-1, preset-2" placeholder="This is a placeholder" class="custom class">
<label for="choices-3">Text input that only allows email addresses</label>
<label for="choices-3">Email addresses only</label>
<input id="choices-3" type="text" placeholder="This is a placeholder">
<label for="choices-4">Text input that disables adding items (destroyed)</label>
<label for="choices-4">Disabled</label>
<input id="choices-4" type="text" value="josh@joshuajohnson.co.uk, joe@bloggs.co.uk" placeholder="This is a placeholder">
<label for="choices-5">Text input that prepends and appends a value to each items return value</label>
<label for="choices-5">Prepends and appends a value to each items return value</label>
<input id="choices-5" type="text" value="preset-1, preset-2" placeholder="This is a placeholder">
<label for="choices-6">Text input with preset values passed through options</label>
<label for="choices-6">Preset values passed through options</label>
<input id="choices-6" type="text" placeholder="This is a placeholder">
<label for="choices-11">Single select box</label>
<select id="choices-11" name="choices-11" data-choice placeholder="This is a placeholder">
<option value="Dropdown item 1">Dropdown item 1</option>
<option value="Dropdown item 2">Dropdown item 2</option>
<option value="Dropdown item 3">Dropdown item 3</option>
</select>
<label for="choices-7">Select box</label>
<h2>Multiple select input</h2>
<label for="choices-7">Default</label>
<select name="choices-7" id="choices-7" placeholder="This is a placeholder" multiple>
<option value="Dropdown item 1">Dropdown item 1</option>
<option value="Dropdown item 2">Dropdown item 2</option>
<option value="Dropdown item 3" selected disabled>Dropdown item 3</option>
<option value="Dropdown item 3" selected>Dropdown item 3</option>
<option value="Dropdown item 4" disabled>Dropdown item 4</option>
</select>
<label for="choices-8">Select box</label>
<select id="choices-8" name="choices-8" data-choice placeholder="This is a placeholder" multiple>
<option value="Dropdown item 1">Dropdown item 1</option>
<option value="Dropdown item 2">Dropdown item 2</option>
<option value="Dropdown item 3">Dropdown item 3</option>
</select>
<label for="choices-9">Select box with pre-selected option</label>
<label for="choices-9">With pre-selected option</label>
<select id="choices-9" name="choices-9" data-choice placeholder="Choose an option" multiple>
<option value="Dropdown item 1">Dropdown item 1</option>
<option value="Dropdown item 2" selected>Dropdown item 2</option>
@ -91,6 +79,17 @@
<option value="Vancouver">Vancouver</option>
</optgroup>
</select>
<h2>Single select input</h2>
<label for="choices-11">Default</label>
<select id="choices-11" name="choices-11" data-choice placeholder="This is a placeholder">
<option value="Dropdown item 1">Dropdown item 1</option>
<option value="Dropdown item 2">Dropdown item 2</option>
<option value="Dropdown item 3">Dropdown item 3</option>
</select>
<label for="choices-12">Options from remote source</label>
<select name="choices-12" id="choices-12" data-choice placeholder="Pick an Arctic Monkeys record"></select>
</div>
</div>
<script>
@ -100,15 +99,6 @@
delimiter: ' ',
editItems: true,
maxItems: 5,
// callbackOnRemoveItem: function(value) {
// console.log(value);
// },
// callbackOnAddItem: function(id, value) {
// console.log(id, value);
// },
// callbackOnRender: function(items) {
// console.log(items);
// }
});
const choices2 = new Choices('#choices-2', {
@ -126,43 +116,35 @@
const choices4 = new Choices('#choices-4', {
addItems: false,
removeItems: false,
});
choices4.destroy();
}).disable();
const choices5 = new Choices('#choices-5', {
prependValue: 'item-',
appendValue: `-${Date.now()}`,
// callbackOnRender: function(items, options) {
// console.log(items);
// },
});
choices5.removeActiveItems();
}).removeActiveItems();
const choices6 = new Choices('#choices-6', {
items: ['josh@joshuajohnson.co.uk', 'joe@bloggs.co.uk'],
// callbackOnRender: function(items, options, groups) {
// console.log(items);
// },
});
const choices7 = new Choices('#choices-7', {
// callbackOnRender: function(items, options) {
// console.log(items);
// },
const choices7 = new Choices('#choices-7');
const choicesAjax = new Choices('#choices-12').ajax((callback) => {
fetch('https://api.discogs.com/artists/391170/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW')
.then((response) => {
response.json().then(function(data) {
callback(data.releases, 'title', 'title');
});
})
.catch((error) => {
callback();
});
});
const choicesMultiple = new Choices('[data-choice]', {
placeholderValue: 'This is a placeholder set in the config',
// callbackOnRender: function(items, options, groups) {
// console.log(options);
// },
});
// choices6.addItem('josh2@joshuajohnson.co.uk', null, null, () => { console.log('Custom add item callback')});
// choices6.removeItemsByValue('josh@joshuajohnson.co.uk');
// console.log(choices6.getItemById(3));
});
</script>
</body>