@kamranbaylarov/one-select 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +848 -0
- package/css/one-select.min.css +37 -0
- package/js/one-select.js +1227 -0
- package/js/one-select.min.js +6 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,848 @@
|
|
|
1
|
+
# 🎯 OneSelect - jQuery Multi-Select Dropdown Component
|
|
2
|
+
|
|
3
|
+
A powerful, flexible, and feature-rich multi-select dropdown component for jQuery.
|
|
4
|
+
|
|
5
|
+
## 📋 Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Overview](#overview)
|
|
8
|
+
2. [Features](#features)
|
|
9
|
+
3. [Installation](#installation)
|
|
10
|
+
4. [All Parameters](#all-parameters)
|
|
11
|
+
5. [Data Attributes](#data-attributes)
|
|
12
|
+
6. [Methods](#methods)
|
|
13
|
+
7. [Callbacks](#callbacks)
|
|
14
|
+
8. [Examples](#examples)
|
|
15
|
+
9. [AJAX Integration](#ajax-integration)
|
|
16
|
+
10. [Form Submission](#form-submission)
|
|
17
|
+
11. [Badge System](#badge-system)
|
|
18
|
+
12. [CSS Styling](#css-styling)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🎯 Overview
|
|
23
|
+
|
|
24
|
+
OneSelect is a powerful **jQuery-based** plugin that provides multi-select functionality with comprehensive customization options.
|
|
25
|
+
|
|
26
|
+
### 🚀 Key Features
|
|
27
|
+
|
|
28
|
+
- ✅ **Multiple Selection** - Select multiple items with checkboxes
|
|
29
|
+
- 🎯 **Select All** - Select all items with one click
|
|
30
|
+
- 🏷️️ **Badge System** - Display selected items as badges
|
|
31
|
+
- 📤 **External Badges** - Display badges in external elements
|
|
32
|
+
- 🔄 **AJAX Support** - Load data dynamically
|
|
33
|
+
- 🔍 **Search Feature** - Local filtering or AJAX search with debounce
|
|
34
|
+
- 📝 **Form Submission** - Submit data via hidden inputs
|
|
35
|
+
- 🎨 **Fully Customizable** - Complete control with 27+ parameters
|
|
36
|
+
- 📱 **Responsive** - Works on all devices
|
|
37
|
+
- 🌐 **Data Attributes** - Configure via HTML attributes
|
|
38
|
+
- 🎪 **Multiple Instances** - Independent selects on same page
|
|
39
|
+
- 🌪 **Click Outside** - Close dropdown when clicking outside (default: true)
|
|
40
|
+
- 📍 **Smart Positioning** - Dropdown positioned with `position: fixed` using viewport coordinates
|
|
41
|
+
- 🔀 **Horizontal Scroll Detection** - Automatically closes on any horizontal scroll to prevent misalignment
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 💡 Features
|
|
46
|
+
|
|
47
|
+
### 📊 Technical Stack
|
|
48
|
+
|
|
49
|
+
| Component | Technology |
|
|
50
|
+
|-----------|------------|
|
|
51
|
+
| **Library** | jQuery (required dependency) |
|
|
52
|
+
| **Plugin Type** | jQuery Plugin |
|
|
53
|
+
| **Files** | `one-select.js`, `one-select.min.css` |
|
|
54
|
+
|
|
55
|
+
### 🎯 Functionality
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
📦 Data Structures:
|
|
59
|
+
├── String Array: ['Apple', 'Banana', 'Cherry']
|
|
60
|
+
└── Object Array: [{id: 1, name: 'Apple'}, ...]
|
|
61
|
+
|
|
62
|
+
🎮 Interactions:
|
|
63
|
+
├── Click to select (checkbox)
|
|
64
|
+
├── "Select All" option
|
|
65
|
+
├── OK button (confirm)
|
|
66
|
+
├── Cancel button (clears selection and closes)
|
|
67
|
+
└── × button (remove from badges)
|
|
68
|
+
|
|
69
|
+
📤 Data Flow:
|
|
70
|
+
├── onChange(values, labels) - When selection changes
|
|
71
|
+
├── onOk(values, labels) - When OK clicked
|
|
72
|
+
├── onCancel() - When Cancel clicked
|
|
73
|
+
└── AJAX callbacks (beforeLoad, afterLoad, onLoadError)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 📦 Installation
|
|
79
|
+
|
|
80
|
+
### 1. Dependencies
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<!-- jQuery must be included first -->
|
|
84
|
+
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. Include Files
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<!-- CSS -->
|
|
91
|
+
<link rel="stylesheet" href="/path/to/one-select.min.css">
|
|
92
|
+
|
|
93
|
+
<!-- JavaScript -->
|
|
94
|
+
<script src="/path/to/one-select.js"></script>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 3. Create HTML Element
|
|
98
|
+
|
|
99
|
+
```html
|
|
100
|
+
<div id="mySelect"></div>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 4. Initialize
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
$('#mySelect').oneSelect({
|
|
107
|
+
data: ['Apple', 'Banana', 'Cherry']
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## ⚙️ All Parameters
|
|
114
|
+
|
|
115
|
+
| Parameter | Type | Default | Description |
|
|
116
|
+
|---------|-----|---------|-------------|
|
|
117
|
+
| `placeholder` | String | `'Select options...'` | Placeholder text when nothing selected |
|
|
118
|
+
| `selectAllText` | String | `'Select All'` | "Select All" button text |
|
|
119
|
+
| `okText` | String | `'OK'` | OK button text |
|
|
120
|
+
| `cancelText` | String | `'Cancel'` | Cancel button text |
|
|
121
|
+
| `data` | Array | `[]` | Options list (string or object array) |
|
|
122
|
+
| `selectedValues` | Array | `[]` | Initially selected values |
|
|
123
|
+
| `value` | String/Array/null | `null` | Single or array value - pre-selects items |
|
|
124
|
+
| `valueField` | String | `'value'` | Value field name in object array |
|
|
125
|
+
| `labelField` | String | `'label'` | Label field name in object array |
|
|
126
|
+
| `showCheckbox` | Boolean | `true` | Show/hide checkboxes |
|
|
127
|
+
| `showBadges` | Boolean | `false` | Show badges in trigger |
|
|
128
|
+
| `showBadgesExternal` | String/null | `null` | External element ID (for badges) |
|
|
129
|
+
| `showSearch` | Boolean | `false` | Show search input in dropdown |
|
|
130
|
+
| `searchPlaceholder` | String | `'Search...'` | Search input placeholder text |
|
|
131
|
+
| `searchUrl` | String/null | `null` | URL for AJAX search (GET request with `q` parameter) |
|
|
132
|
+
| `searchDebounceDelay` | Number | `300` | Delay in milliseconds for search debounce |
|
|
133
|
+
| `closeOnScroll` | Boolean | `false` | Close dropdown on page scroll |
|
|
134
|
+
| `closeOnOutside` | Boolean | `true` | Close dropdown when clicking outside |
|
|
135
|
+
| `submitForm` | Boolean | `false` | Submit form on OK click |
|
|
136
|
+
| `submitOnOutside` | Boolean | `false` | Submit form on outside click |
|
|
137
|
+
| `formId` | String/null | `null` | Specific form ID (null: parent form) |
|
|
138
|
+
| `name` | String/null | `null` | Hidden input name attribute |
|
|
139
|
+
| `multiple` | Boolean | `true` | Submit as array (name[]) |
|
|
140
|
+
| `ajax` | Object/null | `null` | AJAX configuration object |
|
|
141
|
+
| `autoLoad` | Boolean | `true` | Auto load data via AJAX |
|
|
142
|
+
| `beforeLoad` | Function/null | `null` | Called before AJAX |
|
|
143
|
+
| `afterLoad` | Function/null | `null` | Called after AJAX success |
|
|
144
|
+
| `onLoadError` | Function/null | `null` | Called on AJAX error |
|
|
145
|
+
| `onChange` | Function/null | `null` | Called when selection changes |
|
|
146
|
+
| `onSelect` | Function/null | `null` | Previous version of onChange |
|
|
147
|
+
| `onOk` | Function/null | `null` | Called when OK clicked |
|
|
148
|
+
| `onCancel` | Function/null | `null` | Called when Cancel clicked |
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 🏷️ Data Attributes
|
|
153
|
+
|
|
154
|
+
All parameters can be set via HTML data attributes. Data attributes **override JS parameters**.
|
|
155
|
+
|
|
156
|
+
| Data Attribute | Parameter | Type | Example |
|
|
157
|
+
|----------------|----------|-----|---------|
|
|
158
|
+
| `data-ones-placeholder` | `placeholder` | String | `data-ones-placeholder="Select..."` |
|
|
159
|
+
| `data-ones-select-all-text` | `selectAllText` | String | `data-ones-select-all-text="Select All"` |
|
|
160
|
+
| `data-ones-ok-text` | `okText` | String | `data-ones-ok-text="Confirm"` |
|
|
161
|
+
| `data-ones-cancel-text` | `cancelText` | String | `data-ones-cancel-text="Cancel"` |
|
|
162
|
+
| `data-ones-data` | `data` | Array | `data-ones-data='["A","B","C"]'` |
|
|
163
|
+
| `data-ones-selected` | `selectedValues` | Array | `data-ones-selected='["A","C"]'` |
|
|
164
|
+
| `data-ones-value` | `value` | String/Array | `data-ones-value='"A"'` or `data-ones-value='["A","C"]'` |
|
|
165
|
+
| `data-ones-value-field` | `valueField` | String | `data-ones-value-field="id"` |
|
|
166
|
+
| `data-ones-label-field` | `labelField` | String | `data-ones-label-field="name"` |
|
|
167
|
+
| `data-ones-name` | `name` | String | `data-ones-name="items"` |
|
|
168
|
+
| `data-ones-multiple` | `multiple` | Boolean | `data-ones-multiple="true"` |
|
|
169
|
+
| `data-ones-show-checkbox` | `showCheckbox` | Boolean | `data-ones-show-checkbox="false"` |
|
|
170
|
+
| `data-ones-show-badges` | `showBadges` | Boolean | `data-ones-show-badges="true"` |
|
|
171
|
+
| `data-ones-show-badges-external` | `showBadgesExternal` | String | `data-ones-show-badges-external="badgesDiv"` |
|
|
172
|
+
| `data-ones-show-search` | `showSearch` | Boolean | `data-ones-show-search="true"` |
|
|
173
|
+
| `data-ones-search-placeholder` | `searchPlaceholder` | String | `data-ones-search-placeholder="Search items..."` |
|
|
174
|
+
| `data-ones-search-url` | `searchUrl` | String | `data-ones-search-url="/api/search"` |
|
|
175
|
+
| `data-ones-search-debounce-delay` | `searchDebounceDelay` | Number | `data-ones-search-debounce-delay="500"` |
|
|
176
|
+
| `data-ones-close-on-scroll` | `closeOnScroll` | Boolean | `data-ones-close-on-scroll="true"` |
|
|
177
|
+
| `data-ones-close-on-outside` | `closeOnOutside` | Boolean | `data-ones-close-on-outside="true"` |
|
|
178
|
+
| `data-ones-submit-form` | `submitForm` | Boolean | `data-ones-submit-form="true"` |
|
|
179
|
+
| `data-ones-submit-on-outside` | `submitOnOutside` | Boolean | `data-ones-submit-on-outside="true"` |
|
|
180
|
+
| `data-ones-form-id` | `formId` | String | `data-ones-form-id="myForm"` |
|
|
181
|
+
| `data-ones-auto-load` | `autoLoad` | Boolean | `data-ones-auto-load="false"` |
|
|
182
|
+
| `data-ones-ajax` | `ajax` | Object | `data-ones-ajax='{"url": "/api/items"}'` |
|
|
183
|
+
|
|
184
|
+
### Example:
|
|
185
|
+
|
|
186
|
+
```html
|
|
187
|
+
<div id="mySelect"
|
|
188
|
+
data-ones-placeholder="Select products..."
|
|
189
|
+
data-ones-data='["Apple", "Banana", "Cherry"]'
|
|
190
|
+
data-ones-show-badges="true"
|
|
191
|
+
data-ones-name="fruits"
|
|
192
|
+
></div>
|
|
193
|
+
|
|
194
|
+
<script>
|
|
195
|
+
$('#mySelect').oneSelect({
|
|
196
|
+
// JS options (data attributes override these)
|
|
197
|
+
});
|
|
198
|
+
</script>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 🔧 Methods
|
|
204
|
+
|
|
205
|
+
Call via jQuery plugin method:
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
// Get selected values
|
|
209
|
+
var values = $('#mySelect').oneSelect('getValues');
|
|
210
|
+
var labels = $('#mySelect').oneSelect('getLabels');
|
|
211
|
+
|
|
212
|
+
// Set selection
|
|
213
|
+
$('#mySelect').oneSelect('value', ['Apple', 'Banana']);
|
|
214
|
+
|
|
215
|
+
// Update data
|
|
216
|
+
$('#mySelect').oneSelect('updateData', ['New', 'Data']);
|
|
217
|
+
|
|
218
|
+
// Load data via AJAX
|
|
219
|
+
$('#mySelect').oneSelect('loadData');
|
|
220
|
+
|
|
221
|
+
// Selection control
|
|
222
|
+
$('#mySelect').oneSelect('selectAll');
|
|
223
|
+
$('#mySelect').oneSelect('unselectAll');
|
|
224
|
+
$('#mySelect').oneSelect('select', 'Apple');
|
|
225
|
+
$('#mySelect').oneSelect('unselect', 'Banana');
|
|
226
|
+
$('#mySelect').oneSelect('toggleSelection', 'Cherry');
|
|
227
|
+
|
|
228
|
+
// Dropdown control
|
|
229
|
+
$('#mySelect').oneSelect('open');
|
|
230
|
+
$('#mySelect').oneSelect('close');
|
|
231
|
+
|
|
232
|
+
// Get instance ID
|
|
233
|
+
var instanceId = $('#mySelect').oneSelect('getInstanceId');
|
|
234
|
+
|
|
235
|
+
// Get instance object
|
|
236
|
+
var instance = OneSelect.getInstance(instanceId);
|
|
237
|
+
|
|
238
|
+
// Get all instances
|
|
239
|
+
var allInstances = OneSelect.getAllInstances();
|
|
240
|
+
|
|
241
|
+
// Destroy
|
|
242
|
+
$('#mySelect').oneSelect('destroy');
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 🎯 Callbacks
|
|
248
|
+
|
|
249
|
+
### onChange(values, labels)
|
|
250
|
+
|
|
251
|
+
Called every time selection changes. Most important callback.
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
$('#mySelect').oneSelect({
|
|
255
|
+
data: ['A', 'B', 'C'],
|
|
256
|
+
onChange: function(values, labels) {
|
|
257
|
+
console.log('Values:', values);
|
|
258
|
+
console.log('Labels:', labels);
|
|
259
|
+
// values: ['A', 'C']
|
|
260
|
+
// labels: ['A', 'C']
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### onOk(values, labels)
|
|
266
|
+
|
|
267
|
+
Called when OK button is clicked.
|
|
268
|
+
|
|
269
|
+
```javascript
|
|
270
|
+
$('#mySelect').oneSelect({
|
|
271
|
+
onOk: function(values, labels) {
|
|
272
|
+
alert('Selected: ' + labels.join(', '));
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### onCancel()
|
|
278
|
+
|
|
279
|
+
Called when Cancel button is clicked and clears all selections.
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
$('#mySelect').oneSelect({
|
|
283
|
+
onCancel: function() {
|
|
284
|
+
console.log('Selection cancelled');
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### AJAX Callbacks
|
|
290
|
+
|
|
291
|
+
```javascript
|
|
292
|
+
$('#mySelect').oneSelect({
|
|
293
|
+
ajax: {
|
|
294
|
+
url: '/api/items',
|
|
295
|
+
method: 'GET'
|
|
296
|
+
},
|
|
297
|
+
beforeLoad: function() {
|
|
298
|
+
$('#loading').show();
|
|
299
|
+
},
|
|
300
|
+
afterLoad: function(response) {
|
|
301
|
+
$('#loading').hide();
|
|
302
|
+
console.log('Data loaded:', response);
|
|
303
|
+
},
|
|
304
|
+
onLoadError: function(error) {
|
|
305
|
+
$('#error').text('Error: ' + error);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## 📚 Examples
|
|
313
|
+
|
|
314
|
+
### 1. Basic Usage
|
|
315
|
+
|
|
316
|
+
```javascript
|
|
317
|
+
$('#mySelect').oneSelect({
|
|
318
|
+
placeholder: 'Select fruits...',
|
|
319
|
+
data: ['Apple', 'Banana', 'Cherry', 'Mango']
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### 2. Object Array
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
$('#mySelect').oneSelect({
|
|
327
|
+
data: [
|
|
328
|
+
{ id: 1, name: 'Apple', category: 'Fruit' },
|
|
329
|
+
{ id: 2, name: 'Banana', category: 'Fruit' }
|
|
330
|
+
],
|
|
331
|
+
valueField: 'id',
|
|
332
|
+
labelField: 'name'
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### 3. Value Parameter (Pre-selected Items)
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
// Single value
|
|
340
|
+
$('#mySelect').oneSelect({
|
|
341
|
+
data: ['Apple', 'Banana', 'Cherry', 'Mango'],
|
|
342
|
+
value: 'Apple' // 'Apple' will be selected
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// Array with multiple selection
|
|
346
|
+
$('#mySelect').oneSelect({
|
|
347
|
+
data: ['Apple', 'Banana', 'Cherry', 'Mango'],
|
|
348
|
+
value: ['Apple', 'Cherry'], // Both will be selected
|
|
349
|
+
showBadges: true // Enable badge mode
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// HTML data attribute
|
|
353
|
+
<div class="one-select"
|
|
354
|
+
data-ones-data='["Apple", "Banana", "Cherry"]'
|
|
355
|
+
data-ones-value='"Apple"'> <!-- Single value -->
|
|
356
|
+
</div>
|
|
357
|
+
|
|
358
|
+
<!-- OR -->
|
|
359
|
+
<div class="one-select"
|
|
360
|
+
data-ones-data='["Apple", "Banana", "Cherry"]'
|
|
361
|
+
data-ones-value='["Apple", "Cherry"]'> <!-- Array -->
|
|
362
|
+
</div>
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 4. Badge System
|
|
366
|
+
|
|
367
|
+
```javascript
|
|
368
|
+
// Trigger badges
|
|
369
|
+
$('#mySelect').oneSelect({
|
|
370
|
+
data: ['A', 'B', 'C'],
|
|
371
|
+
showBadges: true
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// External badges
|
|
375
|
+
<div id="badgesContainer"></div>
|
|
376
|
+
|
|
377
|
+
$('#mySelect').oneSelect({
|
|
378
|
+
data: ['A', 'B', 'C'],
|
|
379
|
+
showBadgesExternal: 'badgesContainer'
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 5. Form Submission
|
|
384
|
+
|
|
385
|
+
```javascript
|
|
386
|
+
$('#mySelect').oneSelect({
|
|
387
|
+
data: ['Item 1', 'Item 2'],
|
|
388
|
+
name: 'items',
|
|
389
|
+
multiple: true,
|
|
390
|
+
submitForm: true,
|
|
391
|
+
formId: 'myForm'
|
|
392
|
+
});
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Backend example:
|
|
396
|
+
```javascript
|
|
397
|
+
// Receive items array: ['Item 1', 'Item 2']
|
|
398
|
+
// Process filtered items
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### 6. AJAX Data Loading
|
|
402
|
+
|
|
403
|
+
```javascript
|
|
404
|
+
$('#mySelect').oneSelect({
|
|
405
|
+
ajax: {
|
|
406
|
+
url: '/api/categories',
|
|
407
|
+
method: 'GET'
|
|
408
|
+
},
|
|
409
|
+
beforeLoad: function() {
|
|
410
|
+
console.log('Loading...');
|
|
411
|
+
},
|
|
412
|
+
afterLoad: function(response) {
|
|
413
|
+
console.log('Loaded:', response);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### 7. Multiple Instances
|
|
419
|
+
|
|
420
|
+
```javascript
|
|
421
|
+
// Each has independent ID
|
|
422
|
+
var fruits = $('#fruits').oneSelect({
|
|
423
|
+
data: ['Apple', 'Banana', 'Cherry']
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
var colors = $('#colors').oneSelect({
|
|
427
|
+
data: ['Red', 'Blue', 'Green']
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// External control over instances
|
|
431
|
+
var fruitsInstance = OneSelect.getInstance(
|
|
432
|
+
$('#fruits').oneSelect('getInstanceId')
|
|
433
|
+
);
|
|
434
|
+
fruitsInstance.selectAll();
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### 8. Search Feature
|
|
438
|
+
|
|
439
|
+
```javascript
|
|
440
|
+
// Enable local search (filters existing data)
|
|
441
|
+
$('#mySelect').oneSelect({
|
|
442
|
+
data: ['Apple', 'Banana', 'Cherry', 'Mango', 'Orange', 'Grape'],
|
|
443
|
+
showSearch: true,
|
|
444
|
+
searchPlaceholder: 'Type to search...'
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// Enable AJAX search (with debounce)
|
|
448
|
+
$('#mySelect').oneSelect({
|
|
449
|
+
showSearch: true,
|
|
450
|
+
searchUrl: '/api/search',
|
|
451
|
+
searchDebounceDelay: 500,
|
|
452
|
+
searchPlaceholder: 'Search items...'
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// HTML data attribute example (local search)
|
|
456
|
+
<div class="one-select"
|
|
457
|
+
data-ones-data='["Apple", "Banana", "Cherry", "Mango"]'
|
|
458
|
+
data-ones-show-search="true"
|
|
459
|
+
data-ones-search-placeholder="Find a fruit...">
|
|
460
|
+
</div>
|
|
461
|
+
|
|
462
|
+
// HTML data attribute example (AJAX search)
|
|
463
|
+
<div class="one-select"
|
|
464
|
+
data-ones-show-search="true"
|
|
465
|
+
data-ones-search-url="/api/customers/search"
|
|
466
|
+
data-ones-search-debounce-delay="300"
|
|
467
|
+
data-ones-search-placeholder="Search customers...">
|
|
468
|
+
</div>
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**AJAX Search Server Response Format:**
|
|
472
|
+
|
|
473
|
+
The server should respond with JSON in one of these formats:
|
|
474
|
+
|
|
475
|
+
```json
|
|
476
|
+
// Direct array
|
|
477
|
+
["Apple", "Banana", "Cherry"]
|
|
478
|
+
|
|
479
|
+
// Wrapped with 'data'
|
|
480
|
+
{
|
|
481
|
+
"data": [{"value": 1, "label": "Apple"}, {"value": 2, "label": "Banana"}]
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Wrapped with 'results'
|
|
485
|
+
{
|
|
486
|
+
"results": ["Apple", "Banana"]
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
The request will be sent as `GET /api/search?q=searchterm`
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## 📦 Horizontal Scroll Behavior
|
|
495
|
+
|
|
496
|
+
**Automatic dropdown closing on horizontal scroll:**
|
|
497
|
+
|
|
498
|
+
The dropdown automatically closes when the user performs any horizontal scrolling action while the dropdown is open. This prevents the dropdown from appearing in the wrong position when:
|
|
499
|
+
|
|
500
|
+
- Tables with `overflow-x: auto` are scrolled horizontally
|
|
501
|
+
- Any scrollable container is scrolled horizontally
|
|
502
|
+
- Touchpad/trackpad horizontal gestures are used
|
|
503
|
+
- Mouse wheel horizontal scrolling is performed
|
|
504
|
+
|
|
505
|
+
### How It Works
|
|
506
|
+
|
|
507
|
+
The plugin uses two methods to detect horizontal scroll:
|
|
508
|
+
|
|
509
|
+
1. **Wheel Event Detection**: Detects horizontal mouse/touchpad scrolling in real-time
|
|
510
|
+
2. **Periodic Scroll Checking**: Every 50ms, checks if any scrollable element's `scrollLeft` position has changed
|
|
511
|
+
|
|
512
|
+
When horizontal scroll is detected, the dropdown immediately closes.
|
|
513
|
+
|
|
514
|
+
### Example
|
|
515
|
+
|
|
516
|
+
```html
|
|
517
|
+
<div style="overflow-x: auto; width: 100%;">
|
|
518
|
+
<table style="width: 2000px;">
|
|
519
|
+
<tr>
|
|
520
|
+
<td>
|
|
521
|
+
<div id="mySelect"></div>
|
|
522
|
+
</td>
|
|
523
|
+
<td>Other columns...</td>
|
|
524
|
+
</tr>
|
|
525
|
+
</table>
|
|
526
|
+
</div>
|
|
527
|
+
|
|
528
|
+
<script>
|
|
529
|
+
$('#mySelect').oneSelect({
|
|
530
|
+
data: ['Apple', 'Banana', 'Cherry']
|
|
531
|
+
});
|
|
532
|
+
</script>
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**Behavior:**
|
|
536
|
+
- User opens dropdown ✅
|
|
537
|
+
- User scrolls table horizontally → **Dropdown closes automatically** ✅
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## 🔄 AJAX Integration
|
|
542
|
+
|
|
543
|
+
### AJAX Configuration
|
|
544
|
+
|
|
545
|
+
```javascript
|
|
546
|
+
$('#mySelect').oneSelect({
|
|
547
|
+
ajax: {
|
|
548
|
+
url: '/api/items',
|
|
549
|
+
method: 'GET',
|
|
550
|
+
data: { category: 'fruits', active: true }
|
|
551
|
+
},
|
|
552
|
+
autoLoad: false
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
// Manual load
|
|
556
|
+
$('#loadBtn').on('click', function() {
|
|
557
|
+
$('#mySelect').oneSelect('loadData', {
|
|
558
|
+
url: '/api/different-items',
|
|
559
|
+
data: { filter: 'active' }
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Supported Response Formats
|
|
565
|
+
|
|
566
|
+
**1. Direct array:**
|
|
567
|
+
```json
|
|
568
|
+
["Apple", "Banana", "Cherry"]
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
**2. Wrapped with 'data':**
|
|
572
|
+
```json
|
|
573
|
+
{
|
|
574
|
+
"data": ["Apple", "Banana"]
|
|
575
|
+
}
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
**3. Wrapped with 'results':**
|
|
579
|
+
```json
|
|
580
|
+
{
|
|
581
|
+
"results": ["Apple", "Banana"]
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
**4. Object array:**
|
|
586
|
+
```json
|
|
587
|
+
[
|
|
588
|
+
{"value": 1, "label": "Apple"},
|
|
589
|
+
{"value": 2, "label": "Banana"}
|
|
590
|
+
]
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
## 📝 Form Submission
|
|
596
|
+
|
|
597
|
+
### Hidden Inputs
|
|
598
|
+
|
|
599
|
+
Component automatically creates `<input type="hidden">` elements:
|
|
600
|
+
|
|
601
|
+
```javascript
|
|
602
|
+
$('#mySelect').oneSelect({
|
|
603
|
+
name: 'items',
|
|
604
|
+
multiple: true,
|
|
605
|
+
data: ['A', 'B', 'C']
|
|
606
|
+
});
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
HTML result:
|
|
610
|
+
```html
|
|
611
|
+
<input type="hidden" name="items[]" value="A">
|
|
612
|
+
<input type="hidden" name="items[]" value="B">
|
|
613
|
+
<input type="hidden" name="items[]" value="C">
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
## 🏷️ Badge System
|
|
619
|
+
|
|
620
|
+
### Trigger Badges
|
|
621
|
+
|
|
622
|
+
```javascript
|
|
623
|
+
$('#mySelect').oneSelect({
|
|
624
|
+
showBadges: true
|
|
625
|
+
});
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
Result: `[Apple ×] [Banana ×] [Cherry ×]`
|
|
629
|
+
|
|
630
|
+
### External Badges
|
|
631
|
+
|
|
632
|
+
```javascript
|
|
633
|
+
<div id="myBadges"></div>
|
|
634
|
+
|
|
635
|
+
$('#mySelect').oneSelect({
|
|
636
|
+
showBadgesExternal: 'myBadges'
|
|
637
|
+
});
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### Badge Properties
|
|
641
|
+
|
|
642
|
+
- **Background:** `#3b82f6` (light blue)
|
|
643
|
+
- **Text color:** `#fff` (white)
|
|
644
|
+
- **Remove button (×):** `#fff` (white)
|
|
645
|
+
- **Hover:** Light gray background
|
|
646
|
+
- **Remove:** Clicking × button unselects item
|
|
647
|
+
|
|
648
|
+
### Both Together
|
|
649
|
+
|
|
650
|
+
```javascript
|
|
651
|
+
$('#mySelect').oneSelect({
|
|
652
|
+
showBadges: true, // Badge in trigger
|
|
653
|
+
showBadgesExternal: 'myBadges' // Badge outside as well
|
|
654
|
+
});
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## 🎨 CSS Styling
|
|
660
|
+
|
|
661
|
+
Main CSS classes with `cms-` prefix:
|
|
662
|
+
|
|
663
|
+
```css
|
|
664
|
+
.one-select /* Main container (relative positioned) */
|
|
665
|
+
.cms-wrapper /* Wrapper (relative positioned) */
|
|
666
|
+
.cms-trigger /* Button that opens dropdown */
|
|
667
|
+
.cms-selected-text /* Selected text */
|
|
668
|
+
.cms-dropdown /* Dropdown menu (absolute positioned) */
|
|
669
|
+
.cms-search-wrapper /* Search input wrapper */
|
|
670
|
+
.cms-search-input /* Search input field */
|
|
671
|
+
.cms-options-container /* Options container */
|
|
672
|
+
.cms-options-container.cms-loading /* Loading state for AJAX search */
|
|
673
|
+
.cms-option /* Single option */
|
|
674
|
+
.cms-option.selected /* Selected option */
|
|
675
|
+
.cms-option.select-all /* "Select All" option */
|
|
676
|
+
.cms-badge /* Badge */
|
|
677
|
+
.cms-badge-remove /* Badge × button */
|
|
678
|
+
.cms-btn /* OK/Cancel buttons */
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### DOM Structure
|
|
682
|
+
|
|
683
|
+
```html
|
|
684
|
+
<!-- Wrapper element (your container) -->
|
|
685
|
+
<div class="one-select">
|
|
686
|
+
<div class="cms-wrapper">
|
|
687
|
+
<div class="cms-trigger">
|
|
688
|
+
<span class="cms-selected-text">Select...</span>
|
|
689
|
+
</div>
|
|
690
|
+
</div>
|
|
691
|
+
</div>
|
|
692
|
+
|
|
693
|
+
<!-- Dropdown is appended to body with dynamic positioning -->
|
|
694
|
+
<div class="cms-dropdown" style="position: fixed; top: ...; left: ...; width: ...;">
|
|
695
|
+
<!-- Search input (when showSearch is true) -->
|
|
696
|
+
<div class="cms-search-wrapper">
|
|
697
|
+
<input type="text" class="cms-search-input" placeholder="Search...">
|
|
698
|
+
</div>
|
|
699
|
+
<div class="cms-options-container">
|
|
700
|
+
<div class="cms-option select-all">...</div>
|
|
701
|
+
<div class="cms-option">...</div>
|
|
702
|
+
</div>
|
|
703
|
+
<div class="cms-buttons">
|
|
704
|
+
<button class="cms-btn cms-btn-ok">OK</button>
|
|
705
|
+
<button class="cms-btn cms-btn-cancel">Cancel</button>
|
|
706
|
+
</div>
|
|
707
|
+
</div>
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
**Note:** The dropdown is positioned using `position: fixed` with viewport coordinates (`getBoundingClientRect()`). This ensures it stays correctly positioned even when parent elements scroll.
|
|
711
|
+
|
|
712
|
+
### Custom CSS Example
|
|
713
|
+
|
|
714
|
+
```css
|
|
715
|
+
/* Selected option styling */
|
|
716
|
+
.cms-option.selected label {
|
|
717
|
+
font-weight: 600;
|
|
718
|
+
color: #007bff;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/* Badge styling */
|
|
722
|
+
.cms-badge {
|
|
723
|
+
background: #3b82f6;
|
|
724
|
+
color: #fff;
|
|
725
|
+
border-radius: 12px;
|
|
726
|
+
padding: 3px 8px;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/* Search input styling */
|
|
730
|
+
.cms-search-input {
|
|
731
|
+
background: #f8f9fa;
|
|
732
|
+
border-color: #dee2e6;
|
|
733
|
+
}
|
|
734
|
+
.cms-search-input:focus {
|
|
735
|
+
border-color: #3b82f6;
|
|
736
|
+
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/* Custom dropdown width */
|
|
740
|
+
.one-select {
|
|
741
|
+
width: 400px;
|
|
742
|
+
}
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
---
|
|
746
|
+
|
|
747
|
+
## 🚀 Quick Usage Examples
|
|
748
|
+
|
|
749
|
+
```javascript
|
|
750
|
+
// 1. Simple
|
|
751
|
+
$('#select1').oneSelect({
|
|
752
|
+
data: ['A', 'B', 'C']
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
// 2. Object array
|
|
756
|
+
$('#select2').oneSelect({
|
|
757
|
+
data: [{id: 1, title: 'A'}, {id: 2, title: 'B'}],
|
|
758
|
+
valueField: 'id',
|
|
759
|
+
labelField: 'title'
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
// 3. Badges
|
|
763
|
+
$('#select3').oneSelect({
|
|
764
|
+
data: ['X', 'Y', 'Z'],
|
|
765
|
+
showBadges: true
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
// 4. Form submission
|
|
769
|
+
$('#select4').oneSelect({
|
|
770
|
+
data: ['P1', 'P2'],
|
|
771
|
+
name: 'products',
|
|
772
|
+
multiple: true,
|
|
773
|
+
submitForm: true,
|
|
774
|
+
formId: 'myForm'
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
// 5. AJAX
|
|
778
|
+
$('#select5').oneSelect({
|
|
779
|
+
ajax: {url: '/api/items'},
|
|
780
|
+
autoLoad: false
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
// 6. Click outside behavior
|
|
784
|
+
$('#select6').oneSelect({
|
|
785
|
+
closeOnOutside: true // Close when clicking outside (default)
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
// 7. Pre-selected items
|
|
789
|
+
$('#select7').oneSelect({
|
|
790
|
+
data: ['Apple', 'Banana', 'Cherry'],
|
|
791
|
+
value: ['Apple', 'Cherry'] // Pre-select these items
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
// 8. Search feature (local filtering)
|
|
795
|
+
$('#select8').oneSelect({
|
|
796
|
+
data: ['Apple', 'Banana', 'Cherry', 'Mango', 'Orange'],
|
|
797
|
+
showSearch: true,
|
|
798
|
+
searchPlaceholder: 'Search fruits...'
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
// 9. AJAX search with debounce
|
|
802
|
+
$('#select9').oneSelect({
|
|
803
|
+
showSearch: true,
|
|
804
|
+
searchUrl: '/api/search',
|
|
805
|
+
searchDebounceDelay: 500
|
|
806
|
+
});
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
---
|
|
810
|
+
|
|
811
|
+
## 📞 Support
|
|
812
|
+
|
|
813
|
+
**OneSelect** - jQuery Multi-Select Dropdown Component
|
|
814
|
+
|
|
815
|
+
### Project Structure
|
|
816
|
+
|
|
817
|
+
```
|
|
818
|
+
one-select/
|
|
819
|
+
├── css/
|
|
820
|
+
│ └── one-select.min.css
|
|
821
|
+
├── js/
|
|
822
|
+
│ └── one-select.js
|
|
823
|
+
└── README.md
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
### File Locations
|
|
827
|
+
|
|
828
|
+
- **JavaScript:** `one-select/js/one-select.js`
|
|
829
|
+
- **CSS:** `one-select/css/one-select.min.css`
|
|
830
|
+
- **Documentation:** `one-select/README.md`
|
|
831
|
+
|
|
832
|
+
### License
|
|
833
|
+
|
|
834
|
+
MIT License - Feel free to use in your projects!
|
|
835
|
+
|
|
836
|
+
---
|
|
837
|
+
|
|
838
|
+
## 🎯 Browser Support
|
|
839
|
+
|
|
840
|
+
- Chrome (latest)
|
|
841
|
+
- Firefox (latest)
|
|
842
|
+
- Safari (latest)
|
|
843
|
+
- Edge (latest)
|
|
844
|
+
- Opera (latest)
|
|
845
|
+
|
|
846
|
+
---
|
|
847
|
+
|
|
848
|
+
**OneSelect** makes multi-select dropdowns simple and powerful! 🚀
|