Set choice groups via setChoice

This commit is contained in:
Josh Johnson 2016-08-02 21:02:52 +01:00
parent 0ce7c574ea
commit e497999841
3 changed files with 90 additions and 46 deletions

File diff suppressed because one or more lines are too long

View file

@ -316,7 +316,10 @@ export class Choices {
*/ */
showDropdown() { showDropdown() {
this.containerOuter.classList.add(this.config.classNames.openState); this.containerOuter.classList.add(this.config.classNames.openState);
this.containerOuter.setAttribute('aria-expanded', 'true');
this.dropdown.classList.add(this.config.classNames.activeState); this.dropdown.classList.add(this.config.classNames.activeState);
const dimensions = this.dropdown.getBoundingClientRect(); const dimensions = this.dropdown.getBoundingClientRect();
const shouldFlip = this.config.flip ? dimensions.top + dimensions.height >= document.body.offsetHeight : false; const shouldFlip = this.config.flip ? dimensions.top + dimensions.height >= document.body.offsetHeight : false;
@ -341,6 +344,8 @@ export class Choices {
const isFlipped = this.containerOuter.classList.contains(this.config.classNames.flippedState); const isFlipped = this.containerOuter.classList.contains(this.config.classNames.flippedState);
this.containerOuter.classList.remove(this.config.classNames.openState); this.containerOuter.classList.remove(this.config.classNames.openState);
this.containerOuter.setAttribute('aria-expanded', 'false');
this.dropdown.classList.remove(this.config.classNames.activeState); this.dropdown.classList.remove(this.config.classNames.activeState);
if(isFlipped) { if(isFlipped) {
@ -482,11 +487,17 @@ export class Choices {
if(choices && choices.length) { if(choices && choices.length) {
this.containerOuter.classList.remove(this.config.classNames.loadingState); this.containerOuter.classList.remove(this.config.classNames.loadingState);
choices.forEach((result, index) => { choices.forEach((result, index) => {
// Select first choice in list if single select input if(isType('Object', result)) {
if(index === 0 && this.passedElement.type === 'select-one') { const isFirst = index === 0 ? true : false;
this._addChoice(true, result.disabled ? result.disabled : false, result[value], result[label]); this._addGroup(result, index, isFirst);
this.setChoices(result.choices, value, label);
} else { } else {
this._addChoice(result.selected ? result.selected : false, result.disabled ? result.disabled : false, result[value], result[label]); // Select first choice in list if single select input
if(index === 0 && this.passedElement.type === 'select-one') {
this._addChoice(true, result.disabled ? result.disabled : false, result[value], result[label]);
} else {
this._addChoice(result.selected ? result.selected : false, result.disabled ? result.disabled : false, result[value], result[label]);
}
} }
}); });
} }
@ -914,17 +925,16 @@ export class Choices {
if(this.passedElement.type !== 'text') { if(this.passedElement.type !== 'text') {
// For select inputs we always want to show the dropdown if it isn't already showing // For select inputs we always want to show the dropdown if it isn't already showing
this.showDropdown(); this.showDropdown();
if(this.canSearch) { if(this.passedElement.type === 'select-multiple' || this.canSearch) {
this.input.focus(); this.input.focus();
} }
}else{ } else {
// If input is not in focus, it ought to be // If input is not in focus, it ought to be
if(this.input !== document.activeElement) { if(this.input !== document.activeElement) {
this.input.focus(); this.input.focus();
} }
} }
} else if(this.passedElement.type !== 'text' && this.dropdown.classList.contains(this.config.classNames.activeState) && e.target === this.containerInner) {
} else if(this.passedElement.type === 'select-one' && this.dropdown.classList.contains(this.config.classNames.activeState) && e.target === this.containerInner) {
this.hideDropdown(); this.hideDropdown();
} }
@ -1156,6 +1166,7 @@ export class Choices {
// Remove any highlighted choices // Remove any highlighted choices
highlightedChoices.forEach((el) => { highlightedChoices.forEach((el) => {
el.classList.remove(this.config.classNames.highlightedState); el.classList.remove(this.config.classNames.highlightedState);
el.setAttribute('aria-selected', 'false');
}); });
if(el){ if(el){
@ -1175,7 +1186,8 @@ export class Choices {
} }
if(!el) el = choices[0]; if(!el) el = choices[0];
el.classList.add(this.config.classNames.highlightedState); el.classList.add(this.config.classNames.highlightedState);
el.setAttribute('aria-selected', 'true');
} }
} }
} }
@ -1281,13 +1293,13 @@ export class Choices {
* @private * @private
*/ */
_addGroup(group, id, isFirst) { _addGroup(group, id, isFirst) {
const groupChoices = Array.from(group.getElementsByTagName('OPTION')); const groupChoices = isType('Object', group) ? group.choices : Array.from(group.getElementsByTagName('OPTION'));
const groupId = id; const groupId = id;
if(groupChoices) { if(groupChoices) {
this.store.dispatch(addGroup(group.label, groupId, true, group.disabled)); this.store.dispatch(addGroup(group.label, groupId, true, group.disabled));
groupChoices.forEach((option, optionIndex) => { groupChoices.forEach((option) => {
const isDisabled = option.disabled || option.parentNode.disabled; const isDisabled = (option.disabled || option.parentNode && option.parentNode.disabled) || false;
this._addChoice(option.selected, isDisabled, option.value, option.innerHTML, groupId); this._addChoice(option.selected, isDisabled, option.value, option.innerHTML, groupId);
}); });
} else { } else {
@ -1319,11 +1331,11 @@ export class Choices {
containerOuter: () => { containerOuter: () => {
if(this.passedElement.type === 'select-one') { if(this.passedElement.type === 'select-one') {
return strToEl(` return strToEl(`
<div class="${ classNames.containerOuter }" data-type="${ this.passedElement.type }" tabindex="0"></div> <div class="${ classNames.containerOuter }" data-type="${ this.passedElement.type }" tabindex="0" aria-haspopup="true" aria-expanded="false"></div>
`); `);
} else { } else {
return strToEl(` return strToEl(`
<div class="${ classNames.containerOuter }" data-type="${ this.passedElement.type }"></div> <div class="${ classNames.containerOuter }" data-type="${ this.passedElement.type }" aria-haspopup="true" aria-expanded="false"></div>
`); `);
} }
}, },
@ -1350,33 +1362,42 @@ export class Choices {
} }
}, },
choiceList: () => { choiceList: () => {
return strToEl(`<div class="${ classNames.list }"></div>`); return strToEl(`<div class="${ classNames.list }" dir="ltr"></div>`);
}, },
choiceGroup: (data) => { choiceGroup: (data) => {
return strToEl(` return strToEl(`
<div class="${ classNames.group } ${ data.disabled ? classNames.itemDisabled : '' }" data-group data-id="${ data.id }" data-value="${ data.value }"> <div class="${ classNames.group } ${ data.disabled ? classNames.itemDisabled : '' }" data-group data-id="${ data.id }" data-value="${ data.value }" role="group">
<div class="${ classNames.groupHeading }">${ data.value }</div> <div class="${ classNames.groupHeading }">${ data.value }</div>
</div> </div>
`); `);
}, },
choice: (data) => { choice: (data) => {
return strToEl(` if(data.groupId > 0) {
<div class="${ classNames.item } ${ classNames.itemChoice } ${ data.disabled ? classNames.itemDisabled : classNames.itemSelectable }" data-option ${ data.disabled ? 'data-option-disabled' : 'data-option-selectable' } data-id="${ data.id }" data-value="${ data.value }"> return strToEl(`
${ data.label } <div class="${ classNames.item } ${ classNames.itemChoice } ${ data.disabled ? classNames.itemDisabled : classNames.itemSelectable }" data-option ${ data.disabled ? 'data-option-disabled' : 'data-option-selectable' } data-id="${ data.id }" data-value="${ data.value }" role="treeitem">
</div> ${ data.label }
`); </div>
`);
} else {
return strToEl(`
<div class="${ classNames.item } ${ classNames.itemChoice } ${ data.disabled ? classNames.itemDisabled : classNames.itemSelectable }" data-option ${ data.disabled ? 'data-option-disabled' : 'data-option-selectable' } data-id="${ data.id }" data-value="${ data.value }" role="option">
${ data.label }
</div>
`);
}
}, },
input: () => { input: () => {
return strToEl(`<input type="text" class="${ classNames.input } ${ classNames.inputCloned }">`); return strToEl(`<input type="text" class="${ classNames.input } ${ classNames.inputCloned }" autocomplete="off" aria-autocomplete="list" role="textbox">`);
}, },
dropdown: () => { dropdown: () => {
return strToEl(`<div class="${ classNames.list } ${ classNames.listDropdown }"></div>`); return strToEl(`<div class="${ classNames.list } ${ classNames.listDropdown }" aria-expanded="false"></div>`);
}, },
notice: (label, clickable) => { notice: (label, clickable) => {
return strToEl(`<div class="${ classNames.item } ${ classNames.itemChoice }">${ label }</div>`); return strToEl(`<div class="${ classNames.item } ${ classNames.itemChoice }">${ label }</div>`);
}, },
option: (data) => { option: (data) => {
return strToEl(`<option value="${ data.value }" selected>${ data.label }</option>`); return strToEl(`<option value="${ data.value }" selected>${ data.label }</option>`);
}, },
}; };
@ -1418,8 +1439,8 @@ export class Choices {
wrap(containerInner, containerOuter); wrap(containerInner, containerOuter);
// If placeholder has been enabled and we have a value // If placeholder has been enabled and we have a value
if (this.config.placeholder && (this.config.placeholderValue || this.passedElement.placeholder)) { if (this.config.placeholder && (this.config.placeholderValue || this.passedElement.getAttribute('placeholder'))) {
const placeholder = this.config.placeholderValue || this.passedElement.placeholder; const placeholder = this.config.placeholderValue || this.passedElement.getAttribute('placeholder');
input.placeholder = placeholder; input.placeholder = placeholder;
if(this.passedElement.type !== 'select-one') { if(this.passedElement.type !== 'select-one') {
input.style.width = getWidthOfInput(input); input.style.width = getWidthOfInput(input);

View file

@ -44,7 +44,7 @@
<h2>Multiple select input</h2> <h2>Multiple select input</h2>
<label for="choices-7">Default</label> <label for="choices-7">Default</label>
<select name="choices-7" id="choices-7" placeholder="This is a placeholder" multiple> <select data-choice 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 1">Dropdown item 1</option>
<option value="Dropdown item 2">Dropdown item 2</option> <option value="Dropdown item 2">Dropdown item 2</option>
<option value="Dropdown item 3" selected>Dropdown item 3</option> <option value="Dropdown item 3" selected>Dropdown item 3</option>
@ -150,50 +150,51 @@
<option value="0">Zero</option> <option value="0">Zero</option>
</select> </select>
<label for="choices-16">Option selected via config</label> <label for="choices-16">Option and option groups added via config</label>
<select name="choices-16" id="choices-16" placeholder="This is a placeholder"></select> <select name="choices-16" id="choices-16" placeholder="This is a placeholder"></select>
<label for="choices-17">Option selected via config</label>
<select name="choices-17" id="choices-17" placeholder="This is a placeholder"></select>
</div> </div>
</div> </div>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
var choices1 = new Choices(document.getElementById('choices-1'), { var example1 = new Choices(document.getElementById('choices-1'), {
delimiter: ',', delimiter: ',',
editItems: true, editItems: true,
maxItemCount: 5, maxItemCount: 5,
removeItemButton: true removeItemButton: true
}); });
console.log(choices1.getValue()); console.log(example1.getValue());
var choices2 = new Choices('#choices-2', { var example2 = new Choices('#choices-2', {
paste: false, paste: false,
duplicateItems: false, duplicateItems: false,
editItems: true, editItems: true,
}); });
var choices3 = new Choices('#choices-3', { var example3 = new Choices('#choices-3', {
duplicates: false, duplicates: false,
editItems: true, editItems: true,
regexFilter: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, regexFilter: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
}); });
var choices4 = new Choices('#choices-4', { var example4 = new Choices('#choices-4', {
addItems: false, addItems: false,
removeItems: false, removeItems: false,
}).disable(); }).disable();
var choices5 = new Choices('#choices-5', { var example5 = new Choices('#choices-5', {
prependValue: 'item-', prependValue: 'item-',
appendValue: `-${Date.now()}`, appendValue: `-${Date.now()}`,
}).removeActiveItems(); }).removeActiveItems();
var choices6 = new Choices('#choices-6', { var example7 = new Choices('#choices-6', {
items: ['josh@joshuajohnson.co.uk', { value: 'joe@bloggs.co.uk', label: 'Joe Bloggs' } ], items: ['josh@joshuajohnson.co.uk', { value: 'joe@bloggs.co.uk', label: 'Joe Bloggs' } ],
}); });
var choices7 = new Choices('#choices-7', { search: false });
var choices10 = new Choices('#choices-10', { var example8 = new Choices('#choices-10', {
placeholder: true, placeholder: true,
placeholderValue: 'Pick an Strokes record', placeholderValue: 'Pick an Strokes record',
callbackOnChange: function(value, passedInput) { console.log(value) } callbackOnChange: function(value, passedInput) { console.log(value) }
@ -209,7 +210,7 @@
}); });
}); });
var choices12 = new Choices('#choices-12', { var example9 = new Choices('#choices-12', {
placeholder: true, placeholder: true,
placeholderValue: 'Pick an Arctic Monkeys record' placeholderValue: 'Pick an Arctic Monkeys record'
}).ajax(function(callback) { }).ajax(function(callback) {
@ -224,7 +225,7 @@
}); });
}); });
var choices14 = new Choices('#choices-14').ajax(function(callback) { var example10 = new Choices('#choices-14').ajax(function(callback) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('get', 'https://restcountries.eu/rest/v1/all', true); request.open('get', 'https://restcountries.eu/rest/v1/all', true);
request.onreadystatechange = function() { request.onreadystatechange = function() {
@ -243,12 +244,12 @@
request.send(); request.send();
}); });
var choicesMultiple = new Choices('[data-choice]', { var example11 = new Choices('[data-choice]', {
placeholderValue: 'This is a placeholder set in the config', placeholderValue: 'This is a placeholder set in the config',
removeButton: true, removeButton: true,
}); });
var choices15 = new Choices('#choices-15', { var example12 = new Choices('#choices-15', {
choices: [ choices: [
{value: 'One', label: 'Label One'}, {value: 'One', label: 'Label One'},
{value: 'Two', label: 'Label Two', disabled: true}, {value: 'Two', label: 'Label Two', disabled: true},
@ -260,14 +261,36 @@
{value: 'Six', label: 'Label Six', selected: true}, {value: 'Six', label: 'Label Six', selected: true},
], 'value', 'label'); ], 'value', 'label');
var choices16 = new Choices('#choices-16', { var example13 = new Choices('#choices-16', {
placeholder: true,
}).setChoices([{
label: 'Group one',
id: 1,
disabled: false,
choices: [
{value: 'Child One', label: 'Child One', selected: true},
{value: 'Child Two', label: 'Child Two', disabled: true},
{value: 'Child Three', label: 'Child Three'},
]
},
{
label: 'Group two',
id: 2,
disabled: false,
choices: [
{value: 'Child Four', label: 'Child Four', disabled: true},
{value: 'Child Five', label: 'Child Five'},
{value: 'Child Six', label: 'Child Six'},
]
}], 'value', 'label');
var example14 = new Choices('#choices-17', {
choices: [ choices: [
{value: 'One', label: 'Label One'}, {value: 'One', label: 'Label One'},
{value: 'Two', label: 'Label Two', disabled: true}, {value: 'Two', label: 'Label Two', disabled: true},
{value: 'Three', label: 'Label Three'}, {value: 'Three', label: 'Label Three'},
], ],
}).setValueByChoice('Two'); }).setValueByChoice('Two');
}); });
</script> </script>