0
# Event Handling
1
2
Comprehensive event system for responding to slider interactions and value changes with detailed callback information and namespacing support.
3
4
## Capabilities
5
6
### on()
7
8
Binds an event listener to the slider.
9
10
```javascript { .api }
11
/**
12
* Bind an event listener to the slider
13
* @param eventName - Event name, optionally with namespace (e.g., 'update.myNamespace')
14
* @param callback - Function to call when event fires
15
*/
16
slider.noUiSlider.on(eventName: string, callback: EventCallback): void;
17
18
type EventCallback = (
19
values: string[], // Formatted values for all handles
20
handle: number, // Index of the handle that triggered the event
21
unencoded: number[], // Raw numeric values for all handles
22
tap?: boolean, // True if triggered by tap/click
23
positions?: number[], // Handle positions as percentages (0-100)
24
slider?: SliderAPI // Reference to the slider API
25
) => void;
26
```
27
28
**Usage Examples:**
29
30
```javascript
31
// Basic event binding
32
slider.noUiSlider.on('update', function(values, handle) {
33
console.log('Handle', handle, 'updated to:', values[handle]);
34
});
35
36
// Access all callback parameters
37
slider.noUiSlider.on('slide', function(values, handle, unencoded, tap, positions, slider) {
38
console.log('Values:', values); // ["20.00", "80.00"] (formatted)
39
console.log('Handle:', handle); // 1 (active handle index)
40
console.log('Raw values:', unencoded); // [20, 80] (numeric)
41
console.log('Tap event:', tap); // true/false
42
console.log('Positions:', positions); // [20, 80] (percentages)
43
console.log('Slider API:', slider); // Reference to slider
44
});
45
46
// Event with namespace
47
slider.noUiSlider.on('update.validation', function(values) {
48
validateInput(values);
49
});
50
```
51
52
### off()
53
54
Removes event listeners from the slider.
55
56
```javascript { .api }
57
/**
58
* Remove event listeners from the slider
59
* @param eventName - Event name, namespace, or combination to remove
60
*/
61
slider.noUiSlider.off(eventName: string): void;
62
```
63
64
**Usage Examples:**
65
66
```javascript
67
// Remove all listeners for an event
68
slider.noUiSlider.off('update');
69
70
// Remove listeners for specific namespace
71
slider.noUiSlider.off('.validation');
72
73
// Remove specific event with namespace
74
slider.noUiSlider.off('update.validation');
75
76
// Remove all namespaced events
77
slider.noUiSlider.off('.myNamespace');
78
```
79
80
## Event Types
81
82
### start
83
84
Fired when user interaction begins (mousedown, touchstart).
85
86
```javascript { .api }
87
slider.noUiSlider.on('start', callback);
88
```
89
90
**Usage:**
91
92
```javascript
93
slider.noUiSlider.on('start', function(values, handle, unencoded) {
94
console.log('Started dragging handle', handle);
95
document.body.style.cursor = 'grabbing';
96
});
97
```
98
99
### slide
100
101
Fired continuously during user interaction (mousemove, touchmove).
102
103
```javascript { .api }
104
slider.noUiSlider.on('slide', callback);
105
```
106
107
**Usage:**
108
109
```javascript
110
slider.noUiSlider.on('slide', function(values, handle, unencoded) {
111
// Real-time feedback during dragging
112
document.getElementById('current-value').textContent = values[handle];
113
});
114
```
115
116
### update
117
118
Fired when slider values change, from any source.
119
120
```javascript { .api }
121
slider.noUiSlider.on('update', callback);
122
```
123
124
**Usage:**
125
126
```javascript
127
slider.noUiSlider.on('update', function(values, handle, unencoded) {
128
// Update form inputs, display values, etc.
129
document.getElementById('value-' + handle).value = unencoded[handle];
130
});
131
```
132
133
### change
134
135
Fired when user interaction ends and value has changed.
136
137
```javascript { .api }
138
slider.noUiSlider.on('change', callback);
139
```
140
141
**Usage:**
142
143
```javascript
144
slider.noUiSlider.on('change', function(values, handle, unencoded) {
145
// Save to database, validate final value, etc.
146
console.log('Final value changed to:', values[handle]);
147
saveToDatabase(unencoded);
148
});
149
```
150
151
### set
152
153
Fired when values are set programmatically via set() or setHandle().
154
155
```javascript { .api }
156
slider.noUiSlider.on('set', callback);
157
```
158
159
**Usage:**
160
161
```javascript
162
slider.noUiSlider.on('set', function(values, handle, unencoded) {
163
console.log('Value programmatically set to:', values[handle]);
164
});
165
166
// This will trigger the 'set' event
167
slider.noUiSlider.set([30, 70]);
168
```
169
170
### end
171
172
Fired when user interaction ends (mouseup, touchend).
173
174
```javascript { .api }
175
slider.noUiSlider.on('end', callback);
176
```
177
178
**Usage:**
179
180
```javascript
181
slider.noUiSlider.on('end', function(values, handle, unencoded) {
182
console.log('Finished interacting with handle', handle);
183
document.body.style.cursor = '';
184
});
185
```
186
187
### hover
188
189
Fired when hovering over the slider (requires 'hover' behaviour).
190
191
```javascript { .api }
192
slider.noUiSlider.on('hover', callback);
193
```
194
195
**Usage:**
196
197
```javascript
198
// Enable hover behaviour
199
noUiSlider.create(element, {
200
start: 50,
201
range: { min: 0, max: 100 },
202
behaviour: 'hover'
203
});
204
205
// Listen for hover events
206
slider.noUiSlider.on('hover', function(value) {
207
// Note: hover callback receives single value, not array
208
console.log('Hovering over value:', value);
209
showTooltip(value);
210
});
211
```
212
213
## Event Namespacing
214
215
Use namespaces to organize and manage event listeners:
216
217
```javascript
218
// Add namespaced listeners
219
slider.noUiSlider.on('update.ui', updateUI);
220
slider.noUiSlider.on('update.validation', validateValues);
221
slider.noUiSlider.on('change.persistence', saveToDatabase);
222
223
// Remove specific namespace
224
slider.noUiSlider.off('.ui'); // Removes only UI-related listeners
225
slider.noUiSlider.off('.validation'); // Removes only validation listeners
226
227
// Remove specific event with namespace
228
slider.noUiSlider.off('update.ui'); // Removes only UI update listener
229
230
// Multiple namespaces
231
slider.noUiSlider.on('update.ui.form', function(values) {
232
// Update form fields
233
});
234
```
235
236
## Practical Usage Patterns
237
238
### Form Integration
239
240
```javascript
241
// Two-way binding with form inputs
242
const priceRange = document.getElementById('price-range');
243
const minInput = document.getElementById('min-price');
244
const maxInput = document.getElementById('max-price');
245
246
noUiSlider.create(priceRange, {
247
start: [100, 500],
248
connect: true,
249
range: { min: 0, max: 1000 }
250
});
251
252
// Update inputs when slider changes
253
priceRange.noUiSlider.on('update', function(values, handle) {
254
if (handle === 0) {
255
minInput.value = Math.round(values[0]);
256
} else {
257
maxInput.value = Math.round(values[1]);
258
}
259
});
260
261
// Update slider when inputs change
262
minInput.addEventListener('change', function() {
263
priceRange.noUiSlider.set([this.value, null]);
264
});
265
266
maxInput.addEventListener('change', function() {
267
priceRange.noUiSlider.set([null, this.value]);
268
});
269
```
270
271
### Real-time Validation
272
273
```javascript
274
slider.noUiSlider.on('update.validation', function(values, handle, unencoded) {
275
const isValid = unencoded.every(value => value >= 10 && value <= 90);
276
277
if (!isValid) {
278
slider.target.classList.add('invalid');
279
showError('Values must be between 10 and 90');
280
} else {
281
slider.target.classList.remove('invalid');
282
hideError();
283
}
284
});
285
```
286
287
### Debounced API Calls
288
289
```javascript
290
let debounceTimer;
291
292
slider.noUiSlider.on('slide', function(values) {
293
// Clear previous timer
294
clearTimeout(debounceTimer);
295
296
// Set new timer for API call
297
debounceTimer = setTimeout(function() {
298
updateSearchResults(values);
299
}, 300);
300
});
301
302
// Immediate update on final change
303
slider.noUiSlider.on('change', function(values) {
304
clearTimeout(debounceTimer);
305
updateSearchResults(values);
306
});
307
```
308
309
### Multi-slider Coordination
310
311
```javascript
312
// Coordinate multiple related sliders
313
const slider1 = document.getElementById('slider1');
314
const slider2 = document.getElementById('slider2');
315
316
// When slider1 changes, update slider2's range
317
slider1.noUiSlider.on('update.coordination', function(values) {
318
const maxValue = parseFloat(values[0]);
319
320
slider2.noUiSlider.updateOptions({
321
range: {
322
min: 0,
323
max: maxValue
324
}
325
});
326
});
327
```
328
329
### Custom Event Dispatching
330
331
```javascript
332
// Dispatch custom DOM events
333
slider.noUiSlider.on('change', function(values, handle, unencoded) {
334
const event = new CustomEvent('slider-changed', {
335
detail: {
336
values: values,
337
unencoded: unencoded,
338
handle: handle,
339
slider: this
340
}
341
});
342
343
document.dispatchEvent(event);
344
});
345
346
// Listen for custom events elsewhere
347
document.addEventListener('slider-changed', function(event) {
348
console.log('Slider changed:', event.detail);
349
});
350
```
351
352
## Event Callback Parameters
353
354
### values: string[]
355
Formatted values for all handles using the format.to() function.
356
357
```javascript
358
// With custom formatter
359
format: {
360
to: value => '$' + Math.round(value)
361
}
362
363
// values array contains: ["$25", "$75"]
364
```
365
366
### handle: number
367
Zero-based index of the handle that triggered the event.
368
369
```javascript
370
slider.noUiSlider.on('update', function(values, handle) {
371
if (handle === 0) {
372
console.log('First handle changed');
373
} else if (handle === 1) {
374
console.log('Second handle changed');
375
}
376
});
377
```
378
379
### unencoded: number[]
380
Raw numeric values for all handles, not processed by formatters.
381
382
```javascript
383
// Always contains actual numeric values
384
// unencoded: [25, 75] (regardless of formatting)
385
```
386
387
### tap: boolean (optional)
388
True if the event was triggered by a tap/click action.
389
390
```javascript
391
slider.noUiSlider.on('change', function(values, handle, unencoded, tap) {
392
if (tap) {
393
console.log('Value changed by clicking');
394
} else {
395
console.log('Value changed by dragging');
396
}
397
});
398
```
399
400
### positions: number[] (optional)
401
Handle positions as percentages (0-100).
402
403
```javascript
404
slider.noUiSlider.on('update', function(values, handle, unencoded, tap, positions) {
405
console.log('Handle positions:', positions); // [25, 75] (percentages)
406
});
407
```
408
409
### slider: SliderAPI (optional)
410
Reference to the slider API object.
411
412
```javascript
413
slider.noUiSlider.on('update', function(values, handle, unencoded, tap, positions, sliderAPI) {
414
// Access other slider methods
415
const allValues = sliderAPI.get();
416
const options = sliderAPI.options;
417
});
418
```
419
420
## Error Handling
421
422
Event handling is generally robust, but be aware of:
423
424
```javascript
425
// Events fire even for invalid operations
426
slider.noUiSlider.on('update', function(values) {
427
try {
428
updateUI(values);
429
} catch (error) {
430
console.error('Error updating UI:', error);
431
}
432
});
433
434
// Prevent infinite loops in cross-updates
435
let updating = false;
436
slider.noUiSlider.on('update', function(values) {
437
if (updating) return;
438
updating = true;
439
440
// Update related elements
441
updateRelatedSlider(values);
442
443
updating = false;
444
});
445
```