FilteringSelect с помощью QueryReadStore: выбор не привязан - PullRequest
3 голосов
/ 23 января 2009

Я использую dijit.form.FilteringSelect, поддерживаемый dojox.data.QueryReadStore, чтобы позволить пользователю выбрать регион (подумайте о механизме «автозаполнения»). Для каждого символа, введенного пользователем, QueryReadStore отправляет запрос на сервер в ожидании списка соответствующих областей json (со связанными идентификаторами). К тому времени, когда отображается достаточно короткий список, пользователь выбирает нужный элемент. [Следует признать, что запросы при каждом нажатии клавиши - не самый эффективный шаблон, но на данный момент этого достаточно.]

Неожиданное поведение: в некоторых редких, но особых случаях выбор, сделанный пользователем, «не прилипает». Например, если пользователь вводит «can», ему предоставляется следующий выбор в следующем порядке:

Atlantic Canada
Canada
English Canada
Lower Canada
Upper Canada
Western Canada

Если она выбирает среди них «Canada», дижит закрывает выпадающий выбор, правильно выбрав свой выбор. Но к тому времени, как пользователь покидает поле, выбор переключается на «Atlantic Canada»!

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

Я не нашел упоминаний о подобной проблеме нигде. Я вполне готов исследовать, но, поскольку я новичок в додзё, я был бы очень признателен за указатели, прежде чем прибегнуть к углублению в код додзё: где мне сначала взглянуть? Каковы некоторые вероятные проблемы, которые могут вызвать такое поведение? Могу ли я исключить определенные гипотезы? Как мне лучше всего использовать консоль (или Firebug), чтобы добраться до сути этого? и т.д.

Проблема возникает как с dojo 1.1.1, так и с dojo 1.2.3.

Вот (программное) поколение FilteringSelect:

new dijit.form.FilteringSelect({
   name = "region";
   autoComplete = false;
   hasDownArrow = false;
   labelAttr = "name";
   queryExpr = "${0}";
   store = new dojox.data.QueryReadStore({url:'/query/regions'});
}, myNode);

РЕДАКТИРОВАТЬ (2009/02/18): Дополнительные сведения

После ответа Дамелина я хотел понять, что FilteringSelect увидел в этой ситуации. Предположим, что я подключаю функции регистрации к событиям FilteringSelect onChange и onBlur, я получаю следующую последовательность воспроизведения:

  • Я нажимаю в поле и набираю: can
  • Появляется раскрывающийся список 6 регионов (перечисленных выше)
  • с помощью курсоров клавиатуры я перемещаюсь вниз по списку до «Canada» (это регион с идентификатором 1)
  • Я нажимаю Enter (таким образом выбирая пункт магазина). Раскрывающийся список к настоящему времени исчез, и в поле появляется текст "Canada". В этот момент запускается первое событие со следующим журналом:

    onChange event: region 1
    
  • Я покидаю поле, нажимая tab. Здесь два события запускаются одно за другим в следующем порядке:

    onBlur event: region 1
    onChange event: region 246
    

(регион 246 - Atlantic Canada.) Это очень интересно ... К тому времени, как я покидаю поле (onBlur), Canada все еще остается выбранным значением. Таинственный обмен происходит только после этого ...

Ответы [ 6 ]

2 голосов
/ 19 февраля 2009

У меня сегодня была такая же проблема, затрагивающая обе версии Dojo 1.1.1 и 1.2.0.

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

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

На этой странице есть некоторая (неполная) информация: http://www.nabble.com/Problems-with-QueryReadStore-td19269498.html.

Позднее редактировать:

Если вы столкнулись с одной и той же проблемой с FilteringSelect, независимо от того, где находится хранилище данных, там, где есть дубликаты меток.

Например, после того, как виджет потерял фокус, он сбрасывается до первого параметра:

 <select id="coffee2" name="coffee2" 
    dojotype="dijit.form.FilteringSelect" 
    autoComplete="false">
    <script type="dojo/method" event="onChange"  args="newValue">
        console.log(dijit.byId('coffee2').getValue() + '/' + dijit.byId('coffee2').getDisplayedValue());
    </script>
    <option value="0">AAA</option>
    <option value="1">AAA</option>
    <option value="2">AAA</option>
    <option value="3">AAA</option>
    <option value="4">AAA</option>
  </select>

На мой взгляд, это скорее ошибка, чем функция.

2 голосов
/ 01 февраля 2009

Я думаю, что наконец нашел объяснение такого поведения. В нескольких словах, это происходит из-за невыполнения контракта, что FilteringSelect ожидает от QueryReadStore. А поскольку QueryReadStore полностью полагается на ответ от серверного модуля, который генерирует json, он не может выполнить контракт из-за непредвиденного ответа от сервера.

Как я выяснил, в конце пользовательского ввода FilteringSelect ожидает, что Store (в данном случае QueryReadStore) будет возвращать только те элементы, которые точно соответствуют введенной или выбранной строке. FilteringSelect учитывает, что ввод завершается при нажатии клавиши ввода или когда пользователь покидает поле. Перед этим двумя событиями текст, который вводится или выбирается, является просто текстом. На данный момент ни один элемент не выбран.

Другими словами, в конце ввода FilteringSelect ожидает, что Store вернет ноль элементов, если ничего не нужно выбирать, или один элемент, который должен быть выбран. Итак, затем вы предоставляете список регионов, FilteringSelect просто не может определить, какой из них выбрать, и останавливается на первом из них.

Как вы упомянули, QueryReadStore отправляет запрос при каждом нажатии клавиши. В этом случае (до завершения ввода) FilteringSelect ожидает, что Store вернет элементы, соответствующие шаблону. По умолчанию шаблон имеет значение «enterString *», где звездочки - любая последовательность.

Чтобы различать два случая, QueryReadStore слегка варьирует запросы:

  • пример запроса при каждом нажатии клавиши: / query / region? Name = enterString * & start = 0 & count = 5
  • пример запроса в конце ввода: / query / region? Name = enterString & start = 0

Как видите, во втором запросе нет звездочек в конце "enterString". Эти варианты могут помочь построить правильный ответ на стороне сервера.

Надеюсь, я хорошо это объяснил. Если нет, вы можете спросить.

1 голос
/ 01 января 2010

Черт, эта конкретная проблема была настоящей болью в моей заднице тоже !! И вот как я от этого избавился, благодаря ответу damelin.

В моем случае dijit.form.filteringSelect, подкрепленный dojox.data.QueryReadStore, должен был быть заполнен отформатированной строкой, исходящей из множества значений в дБ, полученных из сложных таблиц (с некоторыми родительскими и даже отношениями manyToMany). Пожалуйста, не спрашивайте почему, просто подумайте, что я люблю разделять таблицы БД как можно скорее, чтобы избежать дублирования. Все это в контексте приложения Zend Framework, где QueryReadStore обслуживается действием контроллера, которое я назову здесь autocompletelistAction.

Поэтому, начиная с ответа damelin, я начал работать над моим autocompletelisteAction, чтобы разделить два случая запроса QueryReadStore, считывая параметр GET и его возможную звездочку.

Сначала я очищаю параметр и ищу его последний символ:

$txt = (String) $this->_request->getParam('parameter');
$lastChar = substr($txt, -1);

Тогда, если параметр имеет более 1 символа и не имеет звездочки в конце, я избавлюсь от моего параметра $txt и создам мои подобные предложения вручную:

if ((strlen($txt) >= 1) && ($lastChar != '*')) {
  // here, the parameter is the full text, which the user selected by
  // clicking on a shown element of the filteringSelect

  // Therefore, I "explode" the parameter to correspond to my searched values
  // and I build my SQL LIKE clauses without "%"
  // Consequence? There is only one result which is the good one.
}
else {
  // here, the parameter is a "part" of the search, which the user typed in

  // Therefore, I build my SQL LIKE clauses with "%$txt%"
}
// Here I can just launch my SQL queries with the built LIKE clauses
// and return result(s) to the QueryReadStore

Зачем проверять, является ли $txt более чем одним символом? Потому что в Zend Framework иногда я могу «автозагрузить» filteringSelect со страницей, которая отправляет полностью пустой аргумент (даже без звездочки), который затем переходит к моим «разнесенным» функциям.

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

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

0 голосов
/ 11 ноября 2009

"Для каждого введенного пользователем символа QueryReadStore отправляет запрос на сервер ..."

Можно задать атрибут searchDelay FilteringSelect, который ожидает указанное количество миллисекунд перед отправкой запроса.

0 голосов
/ 30 июля 2009

У нас была такая же проблема. Мы решили, изменив _setDisplayedValueAttr в FilteringSelect.js, чтобы он сразу возвращался:

_setDisplayedValueAttr: function(/*String*/ label, /*Boolean?*/ priorityChange){ return }

Это после того, как мы сломали нам голову на один день, это изменение, очевидно, довольно злое, но оно сработало для нас.

Основная проблема связана с этой строкой в ​​_callbackSetLabel:

this._setValueFromItem(result[0], priorityChange);

Именно поэтому ваше значение устанавливается первым в списке результатов. Я понятия не имею, почему это так.

Надеюсь, у вас все получилось, кстати, мы используем магистральную версию FilteringSelect.js (http://trac.dojotoolkit.org/browser/dijit/trunk/form/FilteringSelect.js)

0 голосов
/ 19 февраля 2009

После комментария pnt ...

В этом обсуждении проясняется, в чем заключается проблема: при "размытии" QueryReadStore повторно запрашивает сервер в последний раз, используя DisplayedValue в качестве строки запроса.

В моем примере это будет "Canada". Учитывая, что шесть областей в моем шорт-листе (см. Далее) содержат эту строку и что мой сервер запрограммирован на возвращение алфавитного списка всех элементов , содержащих строку запроса (а не только те, которые начинаются с нее) снова возвращается весь короткий список, и FilteringSelect выбирает первый элемент среди них --- в данном случае это "Atlantic Canada".

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

...