Фильтрация по началу строки

Фильтрация элементов в Awesomplete по умолчанию реализована как поиск подстроки без строгого ограничения позиции совпадения. Это означает, что совпадение может находиться в любой части строки, и элемент будет показан пользователю даже в случае, если вводимые символы встречаются не в начале значения.

Поведение определяется функцией Awesomplete.filter, которая принимает два аргумента: текст элемента списка и текущее значение ввода. В стандартной реализации используется проверка через регулярное выражение или indexOf, но без ограничения позиции начала строки.

Внутренняя логика библиотеки сводится к следующему принципу:

  • пользователь вводит строку в input;
  • библиотека перебирает элементы списка;
  • каждый элемент проходит через функцию фильтрации;
  • результат true включает элемент в выпадающий список.

Упрощённый вид стандартной фильтрации:

Awesomplete.filter = function (text, input) {
    return text.toLowerCase().indexOf(input.toLowerCase()) > -1;
};

Такой подход обеспечивает гибкий поиск, но не гарантирует совпадение с началом строки.


Ограничение фильтрации началом строки

Для реализации строгого поведения, при котором элементы отображаются только если они начинаются с введённого текста, используется проверка позиции 0.

Ключевая идея:

  • совпадение должно начинаться с первого символа строки;
  • любые вхождения внутри строки игнорируются.

Реализация:

Awesomplete.filter = function (text, input) {
    return text.indexOf(input) === 0;
};

В этом случае:

  • "JavaScript" будет показан при вводе "Ja";
  • "JavaScript" не будет показан при вводе "va".

Регистр и нормализация ввода

В реальных интерфейсах важно учитывать регистр символов. Без нормализации поведение становится чувствительным к регистру, что снижает удобство поиска.

Расширенная версия фильтрации с учётом регистра:

Awesomplete.filter = function (text, input) {
    const value = text.toLowerCase();
    const query = input.toLowerCase();
    return value.indexOf(query) === 0;
};

Здесь выполняется:

  • приведение обеих строк к нижнему регистру;
  • проверка позиции начала строки;
  • исключение любых совпадений внутри строки.

Использование регулярных выражений

Альтернативный способ — применение регулярного выражения с якорем начала строки ^.

Awesomplete.filter = function (text, input) {
    const escaped = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const pattern = new RegExp('^' + escaped, 'i');
    return pattern.test(text);
};

Преимущества подхода:

  • точное выражение условия «с начала строки»;
  • встроенная поддержка регистра через флаг i;
  • возможность расширения логики совпадений.

Недостатки:

  • более высокая стоимость вычислений при больших списках;
  • необходимость экранирования специальных символов.

Работа с объектами списка

Awesomplete поддерживает списки не только из строк, но и из объектов, где отображаемое значение может отличаться от внутреннего.

Пример структуры:

[
    { label: "JavaScript", value: "js" },
    { label: "Java", value: "java" }
]

Фильтрация по началу строки должна учитывать поле label:

Awesomplete.filter = function (text, input) {
    const value = text.label || text;
    return value.toLowerCase().indexOf(input.toLowerCase()) === 0;
};

Такой подход позволяет:

  • фильтровать по пользовательскому отображаемому тексту;
  • сохранять внутренние значения без изменений;
  • обеспечивать корректное отображение результатов.

Интеграция с пользовательскими списками

При использовании динамических данных важно учитывать источник списка. Например, при загрузке данных с сервера:

new Awesomplete(input, {
    list: []
});

После получения данных:

fetch("/api/languages")
    .then(r => r.json())
    .then(data => {
        awesomplete.list = data;
    });

Фильтрация по началу строки автоматически применяется ко всем новым элементам после переопределения Awesomplete.filter.


Комбинирование с кастомной логикой сортировки

Фильтрация часто используется совместно с Awesomplete.sort, которая определяет порядок отображения элементов.

При строгой фильтрации по началу строки сортировка может быть упрощена:

Awesomplete.sort = function (a, b) {
    return a.localeCompare(b);
};

Или полностью отключена логика «похожести», если важен только префикс.


Поведение при пустом вводе

Особенность реализации заключается в том, что при пустом вводе:

  • функция фильтрации возвращает true для всех элементов;
  • список отображается полностью.

При необходимости можно изменить это поведение:

Awesomplete.filter = function (text, input) {
    if (!input) return false;
    return text.toLowerCase().indexOf(input.toLowerCase()) === 0;
};

Теперь список не раскрывается без ввода.


Оптимизация для больших списков

При работе с большим объёмом данных фильтрация по началу строки имеет преимущество:

  • можно использовать индексированные структуры;
  • поиск быстрее, чем полный substring-match;
  • возможна предварительная сортировка по алфавиту.

Дополнительно можно уменьшить количество операций:

Awesomplete.filter = (text, input) => {
    const len = input.length;
    return text.slice(0, len).toLowerCase() === input.toLowerCase();
};

Такой вариант избегает поиска подстроки и работает через сравнение фиксированного фрагмента.


Поведение при локализации и Unicode

При использовании нелатинских алфавитов важно учитывать:

  • разные формы символов;
  • возможные диакритические знаки;
  • нормализацию Unicode.

Расширенный вариант:

Awesomplete.filter = function (text, input) {
    const normalize = str =>
        str.normalize("NFKD").toLowerCase();

    return normalize(text)
        .indexOf(normalize(input)) === 0;
};

Это повышает предсказуемость фильтрации в многоязычных интерфейсах.