aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Zinoviev <me@ch1p.io>2021-05-21 02:29:43 +0300
committerGitHub <noreply@github.com>2021-05-21 02:29:43 +0300
commit603ddb9323a6a1cba6776a87d68c6788a308c7aa (patch)
tree629551368fe194fe24b949709a6248962a082a13
parentdbca6d0a995b2a66a30ace2c4e6e777411594b08 (diff)
parent4c10d574c4360d9d6e52acfdaa8bb87d2319633d (diff)
Merge pull request #6 from sp00n/master
Added the ability to set the label and value key names
-rw-r--r--README.md41
-rw-r--r--autocomplete.js47
2 files changed, 72 insertions, 16 deletions
diff --git a/README.md b/README.md
index fa67f9b..b394308 100644
--- a/README.md
+++ b/README.md
@@ -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 \ No newline at end of file
+MIT
diff --git a/autocomplete.js b/autocomplete.js
index 7a9f151..169d3ed 100644
--- a/autocomplete.js
+++ b/autocomplete.js
@@ -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);
}