【问题标题】:FilteringSelect with a QueryReadStore: selection doesn't stick带有 QueryReadStore 的 FilteringSelect:选择不粘
【发布时间】:2010-10-03 02:11:49
【问题描述】:

我使用由dojox.data.QueryReadStore 支持的dijit.form.FilteringSelect 以允许用户选择一个区域(想想“自动完成”机制)。在用户输入的每个字符上,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 仍然是选定的值。神秘的交换只是在那之后发生......

【问题讨论】:

    标签: json dojo autocomplete


    【解决方案1】:

    我想我终于找到了这种行为的解释。简而言之,它是由于未履行合同而发生的,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”的末尾没有星号。这种变化有助于在服务器端建立正确的响应。

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

    【讨论】:

    • Damelin,很抱歉这么久才回复您。不幸的是,我不认为你的分析反映了我所经历的情况。我将在原始问题中添加详细信息...
    【解决方案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>
    

    在我看来更像是一个错误而不是一个功能。

    【讨论】:

      【解决方案3】:

      该死,这个特殊的问题也让我很头疼!!这就是我摆脱它的方法,感谢 damelin 的回答。

      在我的情况下,dijit.form.filteringSelect 支持的 dijit.form.filteringSelect 需要由来自多个 db 值本身的格式化字符串填充,这些 db 值本身来自复杂表(具有一些父级甚至多对多关系)。请不要问为什么,只要考虑我喜欢尽快分离数据库表,以避免重复。所有这些都在 Zend Framework 应用程序的上下文中,其中 QueryReadStore 由控制器操作提供服务,我将在此处命名为 autocompletelistAction。

      因此,从 damelin 回答开始,我开始处理我的 autocompletelisteAction 以区分 QueryReadStore 请求的两种情况,读取 GET 参数及其最终的星号。

      首先,我清理参数并搜索它的最后一个字符:

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

      然后,如果参数有超过 1 个字符且末尾没有星号,我将摆脱我的 $txt 参数并手动构建我的 like 子句:

      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 框架中,有时我可以用页面“自动加载”filteringSelect,它发送一个完全空的参数(即使没有星号),然后会转到我的“爆炸”函数。

      这个复杂的场景是我的,但我认为每个人都可以在参数上调整这个简单的 PHP 测试,以便提供正确的答案。

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

      【讨论】:

        【解决方案4】:

        关注 pnt 的评论...

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

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

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

        【讨论】:

          【解决方案5】:

          我们遇到了同样的问题。我们通过修改 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)

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-11-28
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多