-
Notifications
You must be signed in to change notification settings - Fork 31
/
bootstrap-4-autocomplete.ts
126 lines (109 loc) · 3.99 KB
/
bootstrap-4-autocomplete.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
interface AutocompleteItem {
value: string,
label: string,
}
interface AutocompleteOptions {
dropdownOptions?: Bootstrap.DropdownOption,
highlightClass?: string,
highlightTyped?: boolean,
label?: string,
maximumItems?: number,
onSelectItem?: (item: AutocompleteItem, element: HTMLElement) => void,
source?: object,
treshold?: number,
value?: string,
}
interface JQuery {
autocomplete(options: AutocompleteOptions): JQuery<HTMLElement>;
}
(function ( $ ) {
let defaults: AutocompleteOptions = {
treshold: 4,
maximumItems: 5,
highlightTyped: true,
highlightClass: 'text-primary',
};
function createItem(lookup: string, item: AutocompleteItem, opts: AutocompleteOptions):string {
let label: string;
if (opts.highlightTyped) {
const idx = item.label.toLowerCase().indexOf(lookup.toLowerCase());
label = item.label.substring(0, idx)
+ '<span class="' + opts.highlightClass + '">' + item.label.substring(idx, idx + lookup.length) + '</span>'
+ item.label.substring(idx + lookup.length, item.label.length);
} else {
label = item.label;
}
return '<button type="button" class="dropdown-item" data-value="' + item.value + '">' + label + '</button>';
}
function createItems(field: JQuery<HTMLElement>, opts: AutocompleteOptions) {
const lookup = field.val() as string;
if (lookup.length < opts.treshold) {
field.dropdown('hide');
return 0;
}
const items = field.next();
items.html('');
let count = 0;
const keys = Object.keys(opts.source);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const object = opts.source[key];
const item = {
label: opts.label ? object[opts.label] : key,
value: opts.value ? object[opts.value]: object,
};
if (item.label.toLowerCase().indexOf(lookup.toLowerCase()) >= 0) {
items.append(createItem(lookup, item, opts));
if (++count >= opts.maximumItems) {
break;
}
}
}
// option action
field.next().find('.dropdown-item').click(function() {
field.val($(this).text());
if (opts.onSelectItem) {
opts.onSelectItem({
value: $(this).data('value'),
label: $(this).text(),
}, field[0]);
}
});
return items.children().length;
}
$.fn.autocomplete = function(options) {
// merge options with default
let opts: AutocompleteOptions = {};
$.extend(opts, defaults, options);
let _field = $(this);
// clear previously set autocomplete
_field.parent().removeClass('dropdown');
_field.removeAttr('data-toggle');
_field.removeClass('dropdown-toggle');
_field.parent().find('.dropdown-menu').remove();
_field.dropdown('dispose');
// attach dropdown
_field.parent().addClass('dropdown');
_field.attr('data-toggle', 'dropdown');
_field.addClass('dropdown-toggle');
_field.after('<div class="dropdown-menu"></div>');
_field.dropdown(opts.dropdownOptions);
this.off('click.autocomplete').click('click.autocomplete', function(e) {
if (createItems(_field, opts) == 0) {
// prevent show empty
e.stopPropagation();
_field.dropdown('hide');
};
});
// show options
this.off('keyup.autocomplete').keyup('keyup.autocomplete', function() {
if (createItems(_field, opts) > 0) {
_field.dropdown('show');
} else {
// sets up positioning
_field.click();
}
});
return this;
};
}( jQuery ));