Могу ли я сделать dijit / form / FilteringSelect менее привередливым?

Я был недоволен тем, как Dijit's FilteringSelect Виджет работает некоторое время, и я возился с Dojo 1.10, пытаясь улучшить его для моего варианта использования. К сожалению, кажется, что никакая комбинация настроек не является правильной, в основном потому, что они не работают вместе.

  • Настройка queryExpr: '*${0}*' хороша, но делает автозаполнение безумным.
  • Установка autoComplete: true удобна, если вы хотите вводить весь текст, начиная с начала, пока не найдете совпадение. К сожалению, если вы хотите начать где-то посередине, это становится головной болью. Конечно, вы можете установить searchDelay: N на что-то достаточно большое, чтобы уловить весь ваш ввод, но как только вы позволите ему возвращать инкрементальные результаты в меню, БАМ ваша способность продолжать печатать и, возможно, в конечном итоге совпадение где-то еще в слове исчезает окно.

Что мне действительно нужно, так это то, что работает так же, как нечеткий поиск в оболочке или приличном текстовом редакторе (например, fzf ). Такие средства поиска пропускают промежуточные символы, в основном разделяя ввод по символам и добавляя между ними неявные подстановочные знаки. Вы продолжаете вводить текст до тех пор, пока первое совпадение не будет тем, которое вам нужно, затем завершите поиск и позвольте ему заменить значение.

Я начал возиться с тем, как это реализовать, но далеко не продвинулся. Я думал об угоне _patternToRegExp(), но быстро обнаружил, что мой store (экземпляр dojo/data/ItemFileReadStore с некоторыми данными JSON) устанавливает флаг _oldAPI и который никогда не исполняется. Я счастлив обновлять магазины, но для меня не очевидно, что это упростит. В результате взлома моего магазина все вышло из-под контроля, и я решил применить менее сложный, но более хакерский подход.

Если вы отключите автозаполнение и установите параметры для сопоставления в середине слов, вы получите список результатов, довольно близкий к тому, что необходимо. Все, что остается сделать пользователю, - это нажать Down один раз после того, как он наберет достаточно ввода, чтобы получить совпадение, и до того, как они Tab уйдут. Тогда возникает вопрос, как избежать необходимости этого ручного вмешательства и стать более снисходительным.

define(["dijit/form/FilteringSelect"], function(FilteringSelect){
return declare("alerque.FuzzyFilter", [FilteringSelect], {
    autoComplete: false,
    highlightMatch: 'all',
    ignoreCase: true,
    queryExpr: '*${0}*',
    searchDelay: 0,

    _patternToRegExp: function(qs) {
        // If this ever actually got called, maybe we could
        // return qs split with wild cards between all characters
        return this.inherited(arguments);
    },

    onblur: function() {
        this._autoCompleteText(this.get('displayedValue'));
        // Pick first match from menu
        return this.inherited(arguments);
    }
})});

Перехват функции onblur() кажется правильным местом для создания виджета, который по умолчанию использует первое совпадение, если вы нажмете табуляцию или щелкнете мышью, но я не могу понять, как на самом деле использовать первое совпадение из меню.

Как мне перейти к более надежному нечеткому поиску с автозаполнением наилучшего соответствия? Мне не нужен ComboBox, значение должно в конечном итоге быть одним из значений в моем наборе данных JSON. В то же время я хочу, чтобы параметры ввода были гораздо более неряшливыми, чем ввод значения с самого начала или необходимость вручную выбирать совпадение.


person Caleb    schedule 30.04.2015    source источник
comment
Какую версию Dojo вы используете? dojo/store/Memory вариант для вас вместо dojo/data/ItemFileReadStore? Это может дать вам больше возможностей / гибкости в конце фильтрации данных ...   -  person Ken Franqueiro    schedule 30.04.2015
comment
@KenFranqueiro Я обновил вопрос этой информацией, но я использую Dojo 1.10, и я рад использовать другой магазин, если это поможет решить эту проблему. Я динамически генерирую данные JSON из базы данных, но это не очень много данных, и я могу преобразовать их в любой формат, который лучше всего подходит, если только виджет пользовательского интерфейса окажется более снисходительным!   -  person Caleb    schedule 30.04.2015
comment
@KenFranqueiro. Поскольку раньше я отвечал, я хотел получить доступ к этим данным из других виджетов и смог преобразовать магазин в dstore/RequestMemory с помощью dstore/legacy/DstoreAdapter, чтобы сделать его совместимым с dijit/FilteringSelect. Не уверен, что это облегчит эту проблему, но это кое-что.   -  person Caleb    schedule 06.05.2015
comment
Не уверен, что вы пытаетесь сделать, но это _patternToRegExp просто замена подстановочного знака *?, которая сбрасывает якоря вокруг него. Это действительно опасно, так как не учитывает буквальные метасимволы.   -  person    schedule 04.06.2015


Ответы (1)


возможно обходной путь / решение для вашего onBlur:

установить queryExpr = "\ $ {0}" без задержки и автозаполнение выключено

При нажатии кнопки filteringSelect вы где-то сохраняете первое значение из всплывающего окна, а затем после onblur измените displayValue / value вашего filteringselect на значение из первого всплывающего окна (если оно было найдено и соответствует ...)

Чтобы получить первое значение из всплывающего окна:

The first shown value can be found in a

  • element with id = YOUR_FILTERING_SELECT_ID + "_popup0"

    поэтому, если ваш id = "mySearchData", ищите идентификатор "mySearchData_popup0"

    если этот элемент существует, сохраните где-нибудь innerHTML (скрытый элемент или var ...)

    Настройте значение из innerHTML, чтобы оно соответствовало значению из магазина:

    Из значения, которое вы получаете из innerHTML, удалите из него элементы диапазона, чтобы он соответствовал одному из значений вашего хранилища данных.

    если ваш идентификатор из вашего filteringselect = "mySearchField" и если вы ищете "123" и первое совпадение во всплывающем окне показывает "тестовый номер 123", тогда значение innerHTML из первого всплывающего окна будет выглядеть следующим образом

    <li id="mySearchField_popup0" class="dijitReset dijitMenuItem" role="option">
    test 
    <span class="dijitComboBoxHighlightMatch">123</span>
    number
    </li>
    

    Итак, немного рисования String (просто удалите теги span из значения innerHTML), и у вас будет значение, которое соответствует вашему первому результату после onblur.

    person 4nti    schedule 08.06.2015
    comment
    Большое спасибо за предложение! Результат не идеален, но это помогает мне частично достичь цели. Я реализовал это немного иначе, чем вы предложили, но основная идея заключается в том, чтобы то же самое: поймать событие размытия и использовать первый элемент во всплывающем окне. Я уверен, что этот код можно улучшить, но мне не удалось найти менее хитрый способ set('value');, чем emit('click') cludge, происходящий здесь. Само значение метки на самом деле не является значением в моем магазине, поэтому я не могу просто его проанализировать. - person Caleb; 10.06.2015