SmartFilter.js

Find What You Need, Instantly!

SmartFilter.js is a powerful JavaScript library that provides advanced filtering capabilities for lists, navigation menus, and other DOM elements. It features fuzzy search with intelligent scoring, performance optimizations, and a robust error handling system.

Pro Tip: SmartFilter.js uses an advanced fuzzy matching algorithm that can find items even when users make typos or only remember part of a name.

Installation

Include the SmartFilter.js script in your HTML file:

<script src="path/to/smartFilter.js"></script>

Basic initialization

// Initialize with default options
var filter = new ListFilter('#navigation-list', '#search-input');

// Or with custom options
var filter = new ListFilter('#navigation-list', '#search-input', {
    debounceWait: 300,
    minLength: 2,
    caseSensitive: false,
    onFilter: function(value) {
        console.log('Filtering with:', value);
    }
});

HTML Structure

<input type="text" id="search-input" placeholder="Search...">
<span class="js-filter-message"></span>

<nav id="navigation-list">
    <ul>
        <li class="nav-title">Category 1</li>
        <li>
            <a href="page1.html">
                <span class="nav-link-text">Page 1</span>
            </a>
        </li>
        <li>
            <a href="page2.html">
                <span class="nav-link-text">Page 2</span>
            </a>
        </li>
        <li class="nav-title">Category 2</li>
        <li>
            <a href="page3.html">
                <span class="nav-link-text">Page 3</span>
            </a>
        </li>
    </ul>
</nav>
Important: For the filter to work correctly, each filterable item should have a <span class="nav-link-text"> element containing the text to be filtered.

Configuration Options

SmartFilter.js offers several configuration options to customize its behavior:

Option Default Value Description Type
anchor null Element to which the filter class will be applied (instead of the list element). Element|string|null
messageSelector '.js-filter-message' Selector for the element that displays the match count. string
debounceWait 250 Time in milliseconds to wait before filtering after input changes. number
minLength 1 Minimum number of characters required to trigger filtering. number
maxLength 100 Maximum number of characters allowed in the search input. number
caseSensitive false Whether the filter should be case-sensitive. boolean
onFilter null Callback function that is called when filtering occurs. Function|null
onReset null Callback function that is called when the filter is reset. Function|null
onError null Callback function that is called when an error occurs. Function|null

Advanced Configuration Example

Here's an example of how to configure SmartFilter with advanced options:

var filter = new ListFilter('#navigation-list', '#search-input', {
    anchor: '#nav-container',
    messageSelector: '.filter-results',
    debounceWait: 300,
    minLength: 2,
    maxLength: 50,
    caseSensitive: false,
    onFilter: function(value) {
        console.log('Filtering with:', value);
        // Update UI or trigger other actions
    },
    onReset: function() {
        console.log('Filter has been reset');
        // Restore original state or trigger other actions
    },
    onError: function(error) {
        console.error('Filter error:', error);
        // Handle errors gracefully
    }
});

Performance Optimizations

SmartFilter.js includes several performance optimizations:

Debouncing

// Debounce function with rate limiting
function debounce(func, wait, immediate) {
    var timeout;
    var lastRun = 0;
    
    return function() {
        var context = this;
        var args = arguments;
        var now = Date.now();
        
        // Rate limiting
        if (now - lastRun < RATE_LIMIT_MS) {
            return;
        }
        
        // Debounce implementation
        clearTimeout(timeout);
        timeout = setTimeout(function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        }, wait);
        
        if (immediate && !timeout) func.apply(context, args);
    };
}

Result Caching

// Cache for fuzzy match results
var fuzzyMatchCache = new Map();

// Check cache before computing match
var cacheKey = pattern + '|' + str;
if (fuzzyMatchCache.has(cacheKey)) {
    return fuzzyMatchCache.get(cacheKey);
}

// Store result in cache
fuzzyMatchCache.set(cacheKey, score);

DOM Caching

// Pre-cache DOM elements
this._cache = {
    items: this.list.getElementsByTagName('a'),
    titles: this.list.getElementsByTagName('li'),
    messageElement: document.querySelector(this.settings.messageSelector),
    size: 0
};
Important: The filter automatically clears caches when they grow too large to prevent memory issues. The maximum cache size is set to 10,000 items.

API Methods

SmartFilter.js exposes several methods for programmatic control:

// Get filter instance
var filter = new ListFilter('#navigation-list', '#search-input');

// Manually trigger filtering
filter.filter();

// Reset the filter (clear input and show all items)
filter.reset();

// Destroy the filter instance and clean up
filter.destroy();

Internal Methods

// Find the navigation title associated with an element
filter.findNavTitle(element);

// Show all parent elements of a given element
filter.showParents(element);

// Show all child elements of a given element
filter.showChildren(element);

Error Handling

SmartFilter.js includes a robust error handling system:

// Error handling with auto-recovery
_handleError: function(error) {
    console.error('ListFilter error:', error);
    
    // Track error frequency
    var now = Date.now();
    if (now - this._lastErrorTime > 60000) {
        this._errorCount = 0;
    }
    
    this._errorCount++;
    this._lastErrorTime = now;
    
    // Call error callback if provided
    if (this.settings.onError) {
        this.settings.onError(error);
    }
    
    // Auto-recovery if too many errors
    if (this._errorCount > 10) {
        this.reset();
        this._errorCount = 0;
    }
}

The error handling system provides:

  • Detailed error logging: Logs errors with context information
  • Error rate tracking: Monitors error frequency
  • Custom error callbacks: Allows custom error handling
  • Auto-recovery: Automatically resets the filter if too many errors occur
  • Input validation: Prevents common errors by validating inputs

Event Handling

SmartFilter.js uses efficient event handling to manage user interactions:

// Bind events with passive listeners for better performance
bindEvents: function() {
    var self = this;
    this.handleFilter = debounce(this.filter.bind(this), this.settings.debounceWait);
    
    // Use passive event listeners for better performance
    this.input.addEventListener('input', this._validateEvent.bind(this), { passive: true });
    this.input.addEventListener('change', this._validateEvent.bind(this), { passive: true });

    // Add ESC key handler
    document.addEventListener('keydown', function(e) {
        if (e.key === 'Escape' || e.key === 'Esc') {
            self.reset();
        }
    });

    // Handle window resize for responsive layouts
    this._resizeHandler = debounce(function() {
        if (self.input.value.length > self.settings.minLength) {
            self.filter();
        }
    }, 250);
    
    window.addEventListener('resize', this._resizeHandler, { passive: true });
}

The filter responds to the following events:

  • input: Triggers filtering when the search input changes
  • change: Triggers filtering when the search input loses focus
  • keydown (Escape): Resets the filter when the Escape key is pressed
  • resize: Re-applies the filter when the window is resized
  • click: Resets the filter when the message element is clicked

CSS Classes

SmartFilter.js uses several CSS classes to manage the visibility of elements:

Class Description Applied To
js-list-filter Indicates that the element is a filterable list List element or anchor element
js-list-active Indicates that the filter is currently active List element
js-filter-hide Hides elements that don't match the filter List items
js-filter-show Shows elements that match the filter List items
nav-title Identifies category titles in the navigation Category title elements
nav-link-text Identifies the text content to be filtered Text elements inside links
Pro Tip: You can style these classes in your CSS to create visual effects when filtering, such as highlighting matched items or fading out hidden items.

Best Practices

  • Set an appropriate debounceWait value (200-300ms is recommended) to balance responsiveness and performance
  • Use the minLength option to prevent filtering on very short inputs
  • Provide a clear visual indication when filtering is active
  • Include a way for users to clear the filter (the filter automatically supports the Escape key)
  • Use the onFilter and onReset callbacks to synchronize other UI elements
  • Implement proper error handling with the onError callback
Pro Tip: For large lists, consider increasing the debounceWait value to reduce the frequency of filtering operations and improve performance.

Troubleshooting

Common Issues:
  • Filter not working? Check that your HTML structure includes <span class="nav-link-text"> elements inside your links.
  • No matches found? Verify that the text content of your items matches what users are searching for.
  • Performance issues? Try increasing the debounceWait value and ensure you're not filtering extremely large lists.
  • Filter showing incorrect results? Check that your navigation titles are properly marked with the nav-title class.
  • Match count not showing? Verify that you have an element matching the messageSelector option.