0
# AJAX Integration
1
2
Remote data loading with customizable request handling, response processing, infinite scrolling, and caching support.
3
4
## Capabilities
5
6
### AJAX Configuration
7
8
Complete configuration interface for remote data loading with extensive customization options.
9
10
```javascript { .api }
11
/**
12
* AJAX configuration options
13
*/
14
interface AjaxOptions {
15
url: string | ((params: AjaxParams) => string);
16
data?: (params: AjaxParams) => object;
17
dataType?: string;
18
delay?: number;
19
cache?: boolean;
20
transport?: (params: TransportParams, success: Function, failure: Function) => void;
21
processResults?: (data: any, params: AjaxParams) => AjaxResponse;
22
23
// All jQuery.ajax options are also supported
24
method?: string;
25
headers?: object;
26
contentType?: string;
27
timeout?: number;
28
}
29
30
/**
31
* AJAX request parameters
32
*/
33
interface AjaxParams {
34
term: string; // Search term entered by user
35
page: number; // Current page number (starts at 1)
36
_type?: string; // Request type: 'query' for standard requests
37
}
38
39
/**
40
* Expected AJAX response format
41
*/
42
interface AjaxResponse {
43
results: DataObject[]; // Array of data objects
44
pagination?: { // Optional pagination info
45
more: boolean; // True if more results available
46
};
47
}
48
49
/**
50
* Transport function parameters
51
*/
52
interface TransportParams {
53
url: string;
54
data: object;
55
success: (data: any) => void;
56
error: (jqXHR: any, textStatus: string, errorThrown: string) => void;
57
}
58
```
59
60
### Basic AJAX Setup
61
62
Simple AJAX configuration for common remote data scenarios.
63
64
```javascript { .api }
65
/**
66
* Basic AJAX configuration
67
*/
68
ajax: {
69
url: string | function, // Request URL or function returning URL
70
dataType: 'json', // Expected response type (default: 'json')
71
delay: 250, // Debounce delay in milliseconds (default: 250)
72
cache: false // Enable request caching (default: false)
73
}
74
```
75
76
**Usage Examples:**
77
78
```javascript
79
// Simple AJAX setup
80
$('#ajax-select').select2({
81
ajax: {
82
url: '/api/users',
83
dataType: 'json'
84
}
85
});
86
87
// Dynamic URL based on context
88
$('#context-select').select2({
89
ajax: {
90
url: function(params) {
91
var contextId = $('#context').val();
92
return '/api/context/' + contextId + '/items';
93
},
94
dataType: 'json',
95
delay: 500
96
}
97
});
98
99
// With custom headers and authentication
100
$('#auth-select').select2({
101
ajax: {
102
url: '/api/secure-data',
103
headers: {
104
'Authorization': 'Bearer ' + authToken,
105
'X-Requested-With': 'XMLHttpRequest'
106
},
107
method: 'POST'
108
}
109
});
110
```
111
112
### Request Data Transformation
113
114
Customize the data sent with AJAX requests to match your API expectations.
115
116
```javascript { .api }
117
/**
118
* Data transformation function
119
*/
120
data?: (params: AjaxParams) => object;
121
```
122
123
**Usage Examples:**
124
125
```javascript
126
// Basic parameter mapping
127
$('#api-select').select2({
128
ajax: {
129
url: '/api/search',
130
data: function(params) {
131
return {
132
q: params.term, // Search term
133
page: params.page, // Page number
134
limit: 10 // Results per page
135
};
136
}
137
}
138
});
139
140
// Complex parameter transformation
141
$('#complex-select').select2({
142
ajax: {
143
url: '/api/complex-search',
144
data: function(params) {
145
var filters = getActiveFilters();
146
var sortOrder = getSortOrder();
147
148
return {
149
query: params.term || '',
150
pagination: {
151
page: params.page || 1,
152
size: 25
153
},
154
filters: filters,
155
sort: sortOrder,
156
timestamp: Date.now()
157
};
158
}
159
}
160
});
161
162
// Conditional parameters
163
$('#conditional-select').select2({
164
ajax: {
165
url: '/api/conditional',
166
data: function(params) {
167
var requestData = {
168
search: params.term
169
};
170
171
// Only include page for pagination requests
172
if (params.page && params.page > 1) {
173
requestData.page = params.page;
174
}
175
176
// Include category filter if selected
177
var category = $('#category-filter').val();
178
if (category) {
179
requestData.category = category;
180
}
181
182
return requestData;
183
}
184
}
185
});
186
```
187
188
### Response Processing
189
190
Transform API responses to match Select2's expected data format.
191
192
```javascript { .api }
193
/**
194
* Response processing function
195
*/
196
processResults?: (data: any, params: AjaxParams) => AjaxResponse;
197
```
198
199
**Usage Examples:**
200
201
```javascript
202
// Basic response transformation
203
$('#transform-select').select2({
204
ajax: {
205
url: '/api/users',
206
processResults: function(data, params) {
207
return {
208
results: data.users.map(function(user) {
209
return {
210
id: user.id,
211
text: user.name + ' (' + user.email + ')'
212
};
213
})
214
};
215
}
216
}
217
});
218
219
// Complex response with pagination
220
$('#paginated-select').select2({
221
ajax: {
222
url: '/api/paginated-data',
223
data: function(params) {
224
return {
225
q: params.term,
226
page: params.page || 1,
227
per_page: 20
228
};
229
},
230
processResults: function(data, params) {
231
params.page = params.page || 1;
232
233
return {
234
results: data.items.map(function(item) {
235
return {
236
id: item.uuid,
237
text: item.display_name,
238
disabled: !item.active
239
};
240
}),
241
pagination: {
242
more: (params.page * 20) < data.total_count
243
}
244
};
245
}
246
}
247
});
248
249
// Grouped results
250
$('#grouped-ajax').select2({
251
ajax: {
252
url: '/api/grouped-data',
253
processResults: function(data, params) {
254
return {
255
results: data.categories.map(function(category) {
256
return {
257
text: category.name,
258
children: category.items.map(function(item) {
259
return {
260
id: item.id,
261
text: item.title
262
};
263
})
264
};
265
})
266
};
267
}
268
}
269
});
270
```
271
272
### Custom Transport
273
274
Override the default AJAX transport for complete control over HTTP requests.
275
276
```javascript { .api }
277
/**
278
* Custom transport function
279
*/
280
transport?: (params: TransportParams, success: Function, failure: Function) => void;
281
```
282
283
**Usage Examples:**
284
285
```javascript
286
// Fetch API transport
287
$('#fetch-select').select2({
288
ajax: {
289
transport: function(params, success, failure) {
290
var requestOptions = {
291
method: 'GET',
292
headers: {
293
'Content-Type': 'application/json'
294
}
295
};
296
297
// Add query parameters to URL
298
var url = new URL(params.url);
299
Object.keys(params.data).forEach(function(key) {
300
url.searchParams.append(key, params.data[key]);
301
});
302
303
fetch(url.toString(), requestOptions)
304
.then(function(response) {
305
if (!response.ok) {
306
throw new Error('Network response was not ok');
307
}
308
return response.json();
309
})
310
.then(success)
311
.catch(failure);
312
},
313
processResults: function(data) {
314
return { results: data };
315
}
316
}
317
});
318
319
// Custom HTTP client transport
320
$('#custom-transport').select2({
321
ajax: {
322
transport: function(params, success, failure) {
323
// Use custom HTTP client (e.g., axios)
324
customHttpClient.get(params.url, {
325
params: params.data,
326
timeout: 5000,
327
headers: {
328
'X-API-Key': getApiKey()
329
}
330
})
331
.then(function(response) {
332
success(response.data);
333
})
334
.catch(function(error) {
335
failure(null, 'error', error.message);
336
});
337
}
338
}
339
});
340
```
341
342
### Infinite Scrolling
343
344
Enable automatic loading of additional results when scrolling to the bottom.
345
346
```javascript { .api }
347
/**
348
* Infinite scrolling is automatically enabled when pagination.more is true
349
*/
350
// Pagination response format
351
interface PaginationResponse {
352
results: DataObject[];
353
pagination: {
354
more: boolean; // Indicates more results available
355
};
356
}
357
```
358
359
**Usage Examples:**
360
361
```javascript
362
// Infinite scroll with page-based pagination
363
$('#infinite-select').select2({
364
ajax: {
365
url: '/api/infinite-data',
366
data: function(params) {
367
return {
368
q: params.term,
369
page: params.page || 1,
370
page_size: 50
371
};
372
},
373
processResults: function(data, params) {
374
params.page = params.page || 1;
375
376
return {
377
results: data.results,
378
pagination: {
379
more: data.has_next_page
380
}
381
};
382
}
383
}
384
});
385
386
// Offset-based infinite scroll
387
$('#offset-select').select2({
388
ajax: {
389
url: '/api/offset-data',
390
data: function(params) {
391
var pageSize = 25;
392
var offset = ((params.page || 1) - 1) * pageSize;
393
394
return {
395
search: params.term,
396
offset: offset,
397
limit: pageSize
398
};
399
},
400
processResults: function(data, params) {
401
params.page = params.page || 1;
402
var pageSize = 25;
403
404
return {
405
results: data.items,
406
pagination: {
407
more: data.total > (params.page * pageSize)
408
}
409
};
410
}
411
}
412
});
413
```
414
415
### Caching and Performance
416
417
Optimize AJAX requests through caching and request management.
418
419
```javascript { .api }
420
/**
421
* Caching configuration
422
*/
423
cache?: boolean; // Enable built-in caching (default: false)
424
delay?: number; // Request debounce delay in ms (default: 250)
425
```
426
427
**Usage Examples:**
428
429
```javascript
430
// Enable caching for static data
431
$('#cached-select').select2({
432
ajax: {
433
url: '/api/static-reference-data',
434
cache: true, // Cache results
435
delay: 100 // Shorter delay for cached data
436
}
437
});
438
439
// Custom caching implementation
440
var customCache = {};
441
442
$('#custom-cache-select').select2({
443
ajax: {
444
transport: function(params, success, failure) {
445
var cacheKey = params.url + '?q=' + (params.data.q || '');
446
447
// Check cache first
448
if (customCache[cacheKey]) {
449
setTimeout(function() {
450
success(customCache[cacheKey]);
451
}, 50);
452
return;
453
}
454
455
// Make request and cache result
456
$.ajax({
457
url: params.url,
458
data: params.data,
459
dataType: 'json'
460
})
461
.done(function(data) {
462
customCache[cacheKey] = data;
463
success(data);
464
})
465
.fail(failure);
466
}
467
}
468
});
469
```
470
471
### Error Handling
472
473
Handle AJAX errors gracefully with user feedback and retry mechanisms.
474
475
```javascript
476
// Basic error handling
477
$('#error-handling-select').select2({
478
ajax: {
479
url: '/api/unreliable-endpoint',
480
transport: function(params, success, failure) {
481
$.ajax({
482
url: params.url,
483
data: params.data,
484
dataType: 'json',
485
timeout: 10000
486
})
487
.done(success)
488
.fail(function(jqXHR, textStatus, errorThrown) {
489
console.error('AJAX Error:', textStatus, errorThrown);
490
491
// Provide user feedback
492
failure(jqXHR, textStatus, 'Failed to load data. Please try again.');
493
});
494
},
495
processResults: function(data, params) {
496
// Handle malformed responses
497
if (!data || !Array.isArray(data.results)) {
498
console.warn('Invalid response format:', data);
499
return { results: [] };
500
}
501
502
return { results: data.results };
503
}
504
}
505
});
506
507
// Retry mechanism
508
function createRetryTransport(maxRetries = 3) {
509
return function(params, success, failure) {
510
var retryCount = 0;
511
512
function attemptRequest() {
513
$.ajax({
514
url: params.url,
515
data: params.data,
516
dataType: 'json',
517
timeout: 5000
518
})
519
.done(success)
520
.fail(function(jqXHR, textStatus, errorThrown) {
521
retryCount++;
522
523
if (retryCount < maxRetries && textStatus !== 'parsererror') {
524
console.log('Retrying request, attempt', retryCount + 1);
525
setTimeout(attemptRequest, 1000 * retryCount);
526
} else {
527
failure(jqXHR, textStatus, errorThrown);
528
}
529
});
530
}
531
532
attemptRequest();
533
};
534
}
535
536
$('#retry-select').select2({
537
ajax: {
538
transport: createRetryTransport(3)
539
}
540
});
541
```