Merge pull request #6 from sp00n/master

Added the ability to set the label and value key names
This commit is contained in:
Evgeny Zinoviev 2021-05-21 02:29:43 +03:00 committed by GitHub
commit 603ddb9323
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 16 deletions

View File

@ -21,12 +21,37 @@ ac.setData([
]);
```
Or use custom label/value keys:
```js
const ac = new Autocomplete(field, {
data: [{name: "entry1", text: "The first entry"}, {name: "entry2", text: "The second entry"}],
label: "name",
value: "text",
onSelectItem: ({label, value}) => {
console.log("user selected:", label, value);
}
});
```
Or use a simple object instead of an array of objects:
```js
const ac = new Autocomplete(field, {
data: {entry1: "The first entry", entry2: "The second entry"},
label: null,
value: null,
onSelectItem: ({label, value}) => {
console.log("user selected:", label, value);
}
});
```
### Options
Options is a JSON object with the following attributes (in alphabetical order):
**data**:
The data from where autocomplete will lookup items to show. This data has to be an array of JSON objects. The format for every item in the array is:
The data from where autocomplete will lookup items to show. This data can be a simple object or an array of JSON objects. By default the format for every object in the array is as following, but you can also change the name of the label and value keys (see below):
{"label": "This is a text", "value": 42}
@ -42,19 +67,29 @@ The class to use when highlighting typed text on items. Only used when highlight
**highlightTyped**:
Wether to highlight (style) typed text on items. Default is true.
**label**:
The name of the `label` key in your data. The label is what will be shown on each item in the autocomplete list.
**maximumItems**:
How many items you want to show when the autocomplete is displayed. Default is 5. Set to 0 to display all available items.
**onInput**
**onInput**:
A callback function to execute on user input.
**onSelectItem**:
A callback that is fired every time an item is selected. It receives an object in following format:
{label: <label>, value: <value>}
**showValue**:
If set to true, will display the value of the entry after the label in the dropdown list.
**treshold**:
The number of characters that need to be typed on the input in order to trigger the autocomplete. Default is 4.
**value**:
The name of the `value` key in your data.
### License
MIT
MIT

View File

@ -3,6 +3,9 @@ const DEFAULTS = {
maximumItems: 5,
highlightTyped: true,
highlightClass: 'text-primary',
label: 'label',
value: 'value',
showValue: false,
};
class Autocomplete {
@ -15,13 +18,13 @@ class Autocomplete {
field.setAttribute('data-bs-toggle', 'dropdown');
field.classList.add('dropdown-toggle');
const dropdown = ce(`<div class="dropdown-menu" ></div>`);
const dropdown = ce(`<div class="dropdown-menu"></div>`);
if (this.options.dropdownClass)
dropdown.classList.add(this.options.dropdownClass);
insertAfter(dropdown, field);
this.dropdown = new bootstrap.Dropdown(field, this.options.dropdownOptions)
this.dropdown = new bootstrap.Dropdown(field, this.options.dropdownOptions);
field.addEventListener('click', (e) => {
if (this.createItems() === 0) {
@ -65,13 +68,19 @@ class Autocomplete {
if (this.options.highlightTyped) {
const idx = item.label.toLowerCase().indexOf(lookup.toLowerCase());
const className = Array.isArray(this.options.highlightClass) ? this.options.highlightClass.join(' ')
: (typeof this.options.highlightClass == 'string' ? this.options.highlightClass : '')
: (typeof this.options.highlightClass == 'string' ? this.options.highlightClass : '');
label = item.label.substring(0, idx)
+ `<span class="${className}">${item.label.substring(idx, idx + lookup.length)}</span>`
+ item.label.substring(idx + lookup.length, item.label.length);
} else
} else {
label = item.label;
return ce(`<button type="button" class="dropdown-item" data-value="${item.value}">${label}</button>`);
}
if (this.options.showValue) {
label += ` ${item.value}`;
}
return ce(`<button type="button" class="dropdown-item" data-label="${item.label}" data-value="${item.value}">${label}</button>`);
}
createItems() {
@ -84,10 +93,17 @@ class Autocomplete {
const items = this.field.nextSibling;
items.innerHTML = '';
const keys = Object.keys(this.options.data);
let count = 0;
for (let i = 0; i < this.options.data.length; i++) {
const {label, value} = this.options.data[i];
const item = {label, value};
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const entry = this.options.data[key];
const item = {
label: this.options.label ? entry[this.options.label] : key,
value: this.options.value ? entry[this.options.value] : entry
};
if (item.label.toLowerCase().indexOf(lookup.toLowerCase()) >= 0) {
items.appendChild(this.createItem(lookup, item));
if (this.options.maximumItems > 0 && ++count >= this.options.maximumItems)
@ -97,13 +113,18 @@ class Autocomplete {
this.field.nextSibling.querySelectorAll('.dropdown-item').forEach((item) => {
item.addEventListener('click', (e) => {
let dataLabel = e.target.getAttribute('data-label');
let dataValue = e.target.getAttribute('data-value');
this.field.value = e.target.innerText;
if (this.options.onSelectItem)
this.field.value = dataLabel;
if (this.options.onSelectItem) {
this.options.onSelectItem({
value: e.target.dataset.value,
label: e.target.innerText,
value: dataValue,
label: dataLabel
});
}
this.dropdown.hide();
})
});
@ -128,5 +149,5 @@ function ce(html) {
* @returns {*}
*/
function insertAfter(elem, refElem) {
return refElem.parentNode.insertBefore(elem, refElem.nextSibling)
return refElem.parentNode.insertBefore(elem, refElem.nextSibling);
}