CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-select2

Select2 is a jQuery based replacement for select boxes with searching, remote data sets, and infinite scrolling support

Pending
Overview
Eval results
Files

ajax.mddocs/

AJAX Integration

Remote data loading with customizable request handling, response processing, infinite scrolling, and caching support.

Capabilities

AJAX Configuration

Complete configuration interface for remote data loading with extensive customization options.

/**
 * AJAX configuration options
 */
interface AjaxOptions {
    url: string | ((params: AjaxParams) => string);
    data?: (params: AjaxParams) => object;
    dataType?: string;
    delay?: number;
    cache?: boolean;
    transport?: (params: TransportParams, success: Function, failure: Function) => void;
    processResults?: (data: any, params: AjaxParams) => AjaxResponse;
    
    // All jQuery.ajax options are also supported
    method?: string;
    headers?: object;
    contentType?: string;
    timeout?: number;
}

/**
 * AJAX request parameters
 */
interface AjaxParams {
    term: string;           // Search term entered by user
    page: number;          // Current page number (starts at 1)
    _type?: string;        // Request type: 'query' for standard requests
}

/**
 * Expected AJAX response format
 */
interface AjaxResponse {
    results: DataObject[];  // Array of data objects
    pagination?: {          // Optional pagination info
        more: boolean;      // True if more results available
    };
}

/**
 * Transport function parameters  
 */
interface TransportParams {
    url: string;
    data: object;
    success: (data: any) => void;
    error: (jqXHR: any, textStatus: string, errorThrown: string) => void;
}

Basic AJAX Setup

Simple AJAX configuration for common remote data scenarios.

/**
 * Basic AJAX configuration
 */
ajax: {
    url: string | function,     // Request URL or function returning URL
    dataType: 'json',          // Expected response type (default: 'json')
    delay: 250,                // Debounce delay in milliseconds (default: 250)
    cache: false               // Enable request caching (default: false)
}

Usage Examples:

// Simple AJAX setup
$('#ajax-select').select2({
    ajax: {
        url: '/api/users',
        dataType: 'json'
    }
});

// Dynamic URL based on context
$('#context-select').select2({
    ajax: {
        url: function(params) {
            var contextId = $('#context').val();
            return '/api/context/' + contextId + '/items';
        },
        dataType: 'json',
        delay: 500
    }
});

// With custom headers and authentication
$('#auth-select').select2({
    ajax: {
        url: '/api/secure-data',
        headers: {
            'Authorization': 'Bearer ' + authToken,
            'X-Requested-With': 'XMLHttpRequest'
        },
        method: 'POST'
    }
});

Request Data Transformation

Customize the data sent with AJAX requests to match your API expectations.

/**
 * Data transformation function
 */
data?: (params: AjaxParams) => object;

Usage Examples:

// Basic parameter mapping
$('#api-select').select2({
    ajax: {
        url: '/api/search',
        data: function(params) {
            return {
                q: params.term,          // Search term
                page: params.page,       // Page number
                limit: 10               // Results per page
            };
        }
    }
});

// Complex parameter transformation
$('#complex-select').select2({
    ajax: {
        url: '/api/complex-search',
        data: function(params) {
            var filters = getActiveFilters();
            var sortOrder = getSortOrder();
            
            return {
                query: params.term || '',
                pagination: {
                    page: params.page || 1,
                    size: 25
                },
                filters: filters,
                sort: sortOrder,
                timestamp: Date.now()
            };
        }
    }
});

// Conditional parameters
$('#conditional-select').select2({
    ajax: {
        url: '/api/conditional',
        data: function(params) {
            var requestData = {
                search: params.term
            };
            
            // Only include page for pagination requests
            if (params.page && params.page > 1) {
                requestData.page = params.page;
            }
            
            // Include category filter if selected
            var category = $('#category-filter').val();
            if (category) {
                requestData.category = category;
            }
            
            return requestData;
        }
    }
});

Response Processing

Transform API responses to match Select2's expected data format.

/**
 * Response processing function
 */
processResults?: (data: any, params: AjaxParams) => AjaxResponse;

Usage Examples:

// Basic response transformation
$('#transform-select').select2({
    ajax: {
        url: '/api/users',
        processResults: function(data, params) {
            return {
                results: data.users.map(function(user) {
                    return {
                        id: user.id,
                        text: user.name + ' (' + user.email + ')'
                    };
                })
            };
        }
    }
});

// Complex response with pagination
$('#paginated-select').select2({
    ajax: {
        url: '/api/paginated-data',
        data: function(params) {
            return {
                q: params.term,
                page: params.page || 1,
                per_page: 20
            };
        },
        processResults: function(data, params) {
            params.page = params.page || 1;
            
            return {
                results: data.items.map(function(item) {
                    return {
                        id: item.uuid,
                        text: item.display_name,
                        disabled: !item.active
                    };
                }),
                pagination: {
                    more: (params.page * 20) < data.total_count
                }
            };
        }
    }
});

// Grouped results
$('#grouped-ajax').select2({
    ajax: {
        url: '/api/grouped-data',
        processResults: function(data, params) {
            return {
                results: data.categories.map(function(category) {
                    return {
                        text: category.name,
                        children: category.items.map(function(item) {
                            return {
                                id: item.id,
                                text: item.title
                            };
                        })
                    };
                })
            };
        }
    }
});

Custom Transport

Override the default AJAX transport for complete control over HTTP requests.

/**
 * Custom transport function
 */
transport?: (params: TransportParams, success: Function, failure: Function) => void;

Usage Examples:

// Fetch API transport
$('#fetch-select').select2({
    ajax: {
        transport: function(params, success, failure) {
            var requestOptions = {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json'
                }
            };
            
            // Add query parameters to URL
            var url = new URL(params.url);
            Object.keys(params.data).forEach(function(key) {
                url.searchParams.append(key, params.data[key]);
            });
            
            fetch(url.toString(), requestOptions)
                .then(function(response) {
                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }
                    return response.json();
                })
                .then(success)
                .catch(failure);
        },
        processResults: function(data) {
            return { results: data };
        }
    }
});

// Custom HTTP client transport
$('#custom-transport').select2({
    ajax: {
        transport: function(params, success, failure) {
            // Use custom HTTP client (e.g., axios)
            customHttpClient.get(params.url, {
                params: params.data,
                timeout: 5000,
                headers: {
                    'X-API-Key': getApiKey()
                }
            })
            .then(function(response) {
                success(response.data);
            })
            .catch(function(error) {
                failure(null, 'error', error.message);
            });
        }
    }
});

Infinite Scrolling

Enable automatic loading of additional results when scrolling to the bottom.

/**
 * Infinite scrolling is automatically enabled when pagination.more is true
 */
// Pagination response format
interface PaginationResponse {
    results: DataObject[];
    pagination: {
        more: boolean;      // Indicates more results available
    };
}

Usage Examples:

// Infinite scroll with page-based pagination
$('#infinite-select').select2({
    ajax: {
        url: '/api/infinite-data',
        data: function(params) {
            return {
                q: params.term,
                page: params.page || 1,
                page_size: 50
            };
        },
        processResults: function(data, params) {
            params.page = params.page || 1;
            
            return {
                results: data.results,
                pagination: {
                    more: data.has_next_page
                }
            };
        }
    }
});

// Offset-based infinite scroll
$('#offset-select').select2({
    ajax: {
        url: '/api/offset-data',
        data: function(params) {
            var pageSize = 25;
            var offset = ((params.page || 1) - 1) * pageSize;
            
            return {
                search: params.term,
                offset: offset,
                limit: pageSize
            };
        },
        processResults: function(data, params) {
            params.page = params.page || 1;
            var pageSize = 25;
            
            return {
                results: data.items,
                pagination: {
                    more: data.total > (params.page * pageSize)
                }
            };
        }
    }
});

Caching and Performance

Optimize AJAX requests through caching and request management.

/**
 * Caching configuration
 */
cache?: boolean;        // Enable built-in caching (default: false)
delay?: number;        // Request debounce delay in ms (default: 250)

Usage Examples:

// Enable caching for static data
$('#cached-select').select2({
    ajax: {
        url: '/api/static-reference-data',
        cache: true,      // Cache results
        delay: 100       // Shorter delay for cached data
    }
});

// Custom caching implementation
var customCache = {};

$('#custom-cache-select').select2({
    ajax: {
        transport: function(params, success, failure) {
            var cacheKey = params.url + '?q=' + (params.data.q || '');
            
            // Check cache first
            if (customCache[cacheKey]) {
                setTimeout(function() {
                    success(customCache[cacheKey]);
                }, 50);
                return;
            }
            
            // Make request and cache result
            $.ajax({
                url: params.url,
                data: params.data,
                dataType: 'json'
            })
            .done(function(data) {
                customCache[cacheKey] = data;
                success(data);
            })
            .fail(failure);
        }
    }
});

Error Handling

Handle AJAX errors gracefully with user feedback and retry mechanisms.

// Basic error handling
$('#error-handling-select').select2({
    ajax: {
        url: '/api/unreliable-endpoint',
        transport: function(params, success, failure) {
            $.ajax({
                url: params.url,
                data: params.data,
                dataType: 'json',
                timeout: 10000
            })
            .done(success)
            .fail(function(jqXHR, textStatus, errorThrown) {
                console.error('AJAX Error:', textStatus, errorThrown);
                
                // Provide user feedback
                failure(jqXHR, textStatus, 'Failed to load data. Please try again.');
            });
        },
        processResults: function(data, params) {
            // Handle malformed responses
            if (!data || !Array.isArray(data.results)) {
                console.warn('Invalid response format:', data);
                return { results: [] };
            }
            
            return { results: data.results };
        }
    }
});

// Retry mechanism
function createRetryTransport(maxRetries = 3) {
    return function(params, success, failure) {
        var retryCount = 0;
        
        function attemptRequest() {
            $.ajax({
                url: params.url,
                data: params.data,
                dataType: 'json',
                timeout: 5000
            })
            .done(success)
            .fail(function(jqXHR, textStatus, errorThrown) {
                retryCount++;
                
                if (retryCount < maxRetries && textStatus !== 'parsererror') {
                    console.log('Retrying request, attempt', retryCount + 1);
                    setTimeout(attemptRequest, 1000 * retryCount);
                } else {
                    failure(jqXHR, textStatus, errorThrown);
                }
            });
        }
        
        attemptRequest();
    };
}

$('#retry-select').select2({
    ajax: {
        transport: createRetryTransport(3)
    }
});

Install with Tessl CLI

npx tessl i tessl/npm-select2

docs

ajax.md

configuration.md

data-management.md

events.md

index.md

initialization.md

theming.md

tile.json