使用QueryReadStore进行FilteringSelect:选择不会粘连

时间:2009-01-23 06:22:11

标签: json dojo autocomplete

我正在使用由dijit.form.FilteringSelect支持的dojox.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 :( / p>)的(程序化)生成

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的事件onChangeonBlur,我会得到以下播放顺序:

  • 我点击该字段并输入: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仍然是选定的值。神秘的交换只发生在......之后......

6 个答案:

答案 0 :(得分:2)

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

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

换句话说,在输入结束时,FilteringSelect要求Store返回零项,如果不应该选择任何内容,或者应该选择一个项。那么,你提供区域列表,FilteringSelect只是无法确定选择哪一个,并在第一个停止。

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

为了区分两种情况,QueryReadStore slighlty改变请求:

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

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

我希望我已经解释得很好。如果没有,欢迎您提出。

答案 1 :(得分: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>

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

答案 2 :(得分:1)

该死的,这个特别的问题在我的屁股上真的很痛!这就是我如何摆脱它,多亏了达梅林的回答。

在我的情况下,dijit.form.filteringSelect支持的dojox.data.QueryReadStore需要由来自复杂表格(具有一些父级甚至许多ToMany关系)的多个db值本身的格式化字符串填充。请不要问为什么,只要考虑我喜欢尽快分离数据库表,以避免重复。所有这些都在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测试,以便提供正确的答案。

所以真正的工作是由damelin here完成的,因为他通过道场元素调查了原因。

答案 3 :(得分:0)

关注pnt的评论......

This discussion明确了问题所在:在“模糊”上,QueryReadStore最后一次使用DisplayedValue作为查询字符串重新查询服务器。 / p>

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

如果我在我的分析中是正确的,那么我可以通过一种可能的方式重构我的查询服务,以便将符合的项目放在列表顶部(按字母顺序排列)查询字符串。

答案 4 :(得分: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

答案 5 :(得分:0)

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

您可以设置FilderingSelect属性searchDelay,它会在发送请求之前等待指定的毫秒数。