3

我正在使用由 adijit.form.FilteringSelect支持的 adojox.data.QueryReadStore以允许用户选择一个区域(想想“自动完成”机制)。在用户输入的每个字符上,QueryReadStore都会向服务器发送一个请求,等待匹配区域的 json 列表(带有关联的 ID)。当显示足够短的列表时,用户选择了所需的项目。[诚然,每次击键查询并不是最有效的模式,但现在已经足够了。]

意外行为:在一些罕见但特定的场合,用户做出的选择“不坚持”。例如,如果用户键入“ can”,她会按顺序看到以下选项:

Atlantic Canada
Canada
English Canada
Lower Canada
Upper Canada
Western Canada

如果她Canada在其中选择“”,dijit 关闭下拉选择,正确选择了她的选择。但是当用户离开该字段时,选择切换到“ Atlantic Canada”!

这种奇怪的现象系统地发生在少数特定地区。(起初,我认为这些行为不端的地区之间的共同因素是它们的名称包含重音字符或连字符,但加拿大的例子显然不是这样。到目前为止,我还没有发现一个规律的模式。)

我在任何地方都没有发现任何类似问题的提及。我非常愿意进行调查,但是,由于我是 dojo 的新手,在我求助于深入研究 dojo 的代码之前,我真的很感激指点:我应该首先看哪里?有哪些可能导致这种行为的问题?我可以排除某些假设吗?我应该如何最好地使用控制台(或 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):附加细节

按照 damelin 的回答,我想了解FilteringSelect这种情况的看法。假设我将日志记录功能连接到FilteringSelect的事件onChange并且onBlur,我得到以下逐个播放序列:

  • 我单击该字段并输入:can
  • 出现 6 个区域的下拉列表(如上所列)
  • 使用键盘光标,我将列表向下移动到“ Canada”(这是 id 为 1 的区域)
  • 我按下Enter(从而选择商店的一个项目)。下拉列表现已消失,文本“ Canada”出现在字段中。此时,第一个事件被触发,记录如下:

    onChange event: region 1
    
  • 我按 离开场地tab。在这里,两个事件一个接一个地被触发,顺序如下:

    onBlur event: region 1
    onChange event: region 246
    

(区域 246 是Atlantic Canada。)现在这很有趣......当我离开该字段时(onBlur),Canada仍然是选定的值。神秘的交换在那之后才发生……

4

6 回答 6

2

我想我终于找到了这种行为的解释。简而言之,这是由于未履行合同而发生的,FilteringSelect 期望 QueryReadStore 履行合同。由于 QueryReadStore 完全依赖于生成 json 的服务器模块的响应,因此由于服务器的意外响应而无法履行合同。

正如我所知道的,在用户输入结束时, FilteringSelect 期望 Store(在这种情况下为 QueryReadStore)只返回与输入或选择的字符串完全匹配的项目。FilteringSelect 认为输入在按下输入键或用户离开字段时结束。在这两个事件之前,输入或选择的文本只是文本。目前没有实际选择任何项目。

换句话说,在输入结束时,FilteringSelect 期望 Store 如果不应该选择任何内容,则返回零个项目,或者应该选择一个项目。因此,然后您提供区域列表,FilteringSelect 只是无法确定选择哪个区域,并且首先停止。

正如您所提到的,QueryReadStore 在每次击键时都会发送请求。在这种情况下(在输入结束之前)FilteringSelect 期望 Store 返回匹配模式的项目。默认模式是“ enteredString * ”,其中星号是任何序列。

为了区分两种情况,QueryReadStore 会稍微改变请求:

  • 每次击键时的示例请求:/query/regions?name=enteredString*&start=0&count=5
  • 输入结束时的示例请求:/query/regions?name=enteredString&start=0

如您所见,在第二个请求中,“enteredString”的末尾没有星号。这种变化可以帮助在服务器端建立正确的响应。

我希望我已经解释清楚了。如果没有,欢迎您询问。

于 2009-02-01T10:47:35.033 回答
2

我今天遇到了同样的问题,影响了 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>

在我看来,更多的是一个错误而不是一个功能。

于 2009-02-19T05:58:54.317 回答
1

Damn, this particular problem was a real pain in my ass too!! And here is how I got rid of it, thanks to damelin answer.

In my case, the dijit.form.filteringSelect backed by a dojox.data.QueryReadStore was needed to be filled by a formatted string coming from multiple db values itself coming from complex tables (with some parent and even manyToMany relationship). Please don't ask why, just consider I love separating db tables as soon as possible, in order to avoid duplicates. All of that is in the context of a Zend Framework application, where the QueryReadStore is served by a controller action which I'll name here autocompletelistAction.

Therefore, starting from damelin answer, I began working on my autocompletelisteAction to separate the two cases of QueryReadStore request, reading the GET parameter and its eventual asterisk.

First, I clean the parameter and search for its last char :

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

Then, if the parameter has more than 1 char and no asterisk at the end, I'm gonna get rid of my $txt parameter and build my like clauses by hand :

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

Why checking if $txt is more than one char? Because within the Zend Framework, sometimes I can "autoload" the filteringSelect with the page, which sends a fully empty argument (even without asterisk), which then would go to my "explode" functions.

This complex scenario is mine, but I think each could adapt this simple PHP test on the parameter in order to serve the right answer.

So the real job was done by damelin here because he investigated the reasons through dojo elements.

于 2010-01-01T14:40:32.007 回答
0

我们遇到了同样的问题。我们通过修改 FilteringSelect.js 中的 _setDisplayedValueAttr 以立即返回来解决:

_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

于 2009-07-30T11:06:52.170 回答
0

按照 pnt 的评论...

这个讨论清楚地说明了问题出在哪里:在“模糊”上,QueryReadStore最后一次重新查询服务器,使用DisplayedValue作为它的查询字符串。

在我的示例中,这将是“ Canada”。鉴于我的候选名单中的六个区域(见进一步)包含该字符串,并且我的服务器被编程为返回包含查询字符串的所有项目的字母列表(而不仅仅是那些以它开头的项目),整个候选名单再次是返回,然后FilteringSelect选择其中的第一项 --- 在本例中为“ Atlantic Canada”。

如果我的分析是正确的,那么一种可能的前进方式是我重构我的查询服务,以便将与查询字符串完全匹配的任何项目放在列表的顶部(在字母顺序之前)。

于 2009-02-19T06:53:47.103 回答
0

“在用户输入的每个字符上,QueryReadStore 都会向服务器发送一个请求......”

有FilteringSelect属性searchDelay可以设置,在发送请求前等待指定的毫秒数。

于 2009-11-11T14:51:34.353 回答