Choices.js – фильтрация поиска на стороне сервера

Вопрос или проблема

Я хочу использовать Choices JS в качестве интерфейса для фильтрации поиска на стороне сервера. Демонстрация включает только загрузку всего списка и фильтрацию на стороне клиента – у меня слишком много записей, чтобы это было жизнеспособно.

Я заставил это работать, за исключением одной вещи: когда вы печатаете, поле поиска теряет фокус, что делает его почти unusable с точки зрения пользовательского опыта.

У меня пока что это (обратите внимание, что это завернуто в связывание Knockout и использует таймаут как фиктивный запрос):

(function()
{
    var _getConfig = function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
    {
        var cfg = ko.unwrap(f_valueaccessor());

        var res = {
            obs: cfg.boundField,
            src: cfg.src,
            multiple: ko.unwrap(cfg.multiple) || false,
            options: cfg.options || {},
            _current: cfg.items || ko.observableArray()
        };

        return res;
    };

    ko.bindingHandlers.choices = {
        init:
            function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
            {
                var cfg = _getConfig(el, f_valueaccessor, allbindings, viewmodel, bindingcontext);
                cfg.multiple && el.setAttribute('multiple');

                var chc = new Choices(el, {
                    searchChoices: false,
                    shouldSort: false,
                    shouldSortItems: false
                });
                
                chc.setChoices(function()
                {
                    return cfg.src(chc, { initial: true, term: null });
                });

                el.addEventListener('search', function(e)
                {
                    console.log('поиск', e);
                    chc.setChoices(function() { return cfg.src(chc, { initial: false, term: e.detail.value }) });
                });
            },
        update:
            function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
            {
            }
    };
})();

var model = new function()
{
    this.Choice = ko.observableArray();
    this.IsMultiple = ko.observable(false);

    this.find = function(sender, eargs)
    {
        return new Promise(function(resolve)
        {
            setTimeout(function()
            {
                resolve([{ value: 1, label: 'Привет' }, { value: 2, label: 'Мир' }]);
            }, 100);
        });
    };
};

ko.applyBindings(model);

Работающая петля: https://jsfiddle.net/whelkaholism/5sn9wt0r/22/

ОБНОВЛЕНИЕ:

Я изменил обработчик события поиска на приведенный ниже и он работает, но кажется довольно хакерским, есть ли лучший способ?

el.addEventListener('search', function(e)
                {
                    console.log('поиск', e, chc);
                    
                    chc.setChoices(function() { 
                        return new Promise(function(resolve){
                        cfg.src(chc, { initial: false, term: e.detail.value }).then(function(data) {
                            resolve(data);
                          
                          setTimeout(function() {chc.choiceList.element.parentElement.querySelector('input[type=search]').focus(); }, 0);
                        });
                      });
                     });
                });

Ответ или решение

Вопрос о Choices.js: Фильтрация поиска на серверной стороне

Использование библиотеки Choices.js в качестве пользовательского интерфейса для фильтрации поиска на серверной стороне – это довольно распространённая задача, особенно когда количество записей слишком велико для загрузки и фильтрации на клиенте. Если вы столкнулись с проблемой, когда поле поиска теряет фокус во время ввода, это влияет на пользовательский опыт (UX) и может вызвать недовольство пользователей.

Анализ Вашего Решения

Учитывая ваше текущее решение, вы используете стандартные функции библиотеки Choices.js в сочетании с Knockout.js. Ваша реализация позволяет загружать данные асинхронно по мере ввода текста в поисковое поле, но, как вы отметили, фокус на поле теряется, что делает процесс неинтуитивным.

Текущий Код

Ваш текущий обработчик события поиска:

el.addEventListener('search', function(e) {
    console.log('search', e, chc);

    chc.setChoices(function() { 
        return new Promise(function(resolve){ 
            cfg.src(chc, { initial: false, term: e.detail.value }).then(function(data) {
                resolve(data);
                setTimeout(function() {
                    chc.choiceList.element.parentElement.querySelector('input[type=search]').focus();
                }, 0);
            });
        });
    });
});

Хотя это решение работает, оно действительно выглядит "хакерским". Давайте рассмотрим более элегантный способ:

Оптимизированный Подход

  1. Сохранение Фокуса: Вместо использования setTimeout, что может быть ненадёжным, сохраните фокус при каждом обновлении списка выбора. Мы также можем использовать метод render для вызова обновления компонента.

  2. Использование Асинхронных Функций: Вместо промисов и вложенных функций, используйте async/await, что значительно улучшит читаемость кода.

Вот пример улучшенного обработчика:

el.addEventListener('search', async function(e) {
    console.log('search', e, chc);

    chc.setChoices(async () => {
        const data = await cfg.src(chc, { initial: false, term: e.detail.value });
        return data;
    });

    // Сохраняем фокус на поле поиска после обновления
    e.target.focus();
});

Итоги

Таким образом, для улучшения пользовательского опыта с Choices.js в контексте серверной фильтрации поиска, вам следует:

  • Использовать async/await для повышения читабельности кода.
  • Сохранять фокус на поле поиска с помощью e.target.focus() вместо хаков с setTimeout.

Такой подход не только улучшит UX, но и сделает ваш код более чистым и простым в обслуживании.

Дополнительные Рекомендации

  • Оптимизация Запросов на Сервер: Убедитесь, что ваш сервер обрабатывает запросы как можно быстрее. Использование кэширования может значительно сократить время отклика.
  • Пользовательские Сообщения: Если результат поиска не найден, обязательно сообщайте пользователю об этом, чтобы избежать путаницы.

Следуя этим рекомендациям, вы сможете создать более стабильный и интуитивно понятный интерфейс поиска с использованием Choices.js.

Оцените материал
Добавить комментарий

Капча загружается...