【问题标题】:Can I make dijit/form/FilteringSelect less persnickety?我可以让 dijit/form/FilteringSelect 不那么挑剔吗?
【发布时间】:2015-04-30 13:38:31
【问题描述】:

一段时间以来,我一直对Dijit's FilteringSelect 小部件的工作方式不满意,并且一直在尝试使用Dojo 1.10 来改进它以适应我的用例。不幸的是,似乎没有一种设置组合是完全正确的,主要是因为它们不能一起工作。

  • 设置 queryExpr: '*${0}*' 很好,但它会让自动完成变得疯狂。
  • 设置autoComplete: true 很好,只要您想从头开始输入整个文本,直到找到匹配项。不幸的是,如果您想从中间的某个地方开始,那将变得很痛苦。当然,您可以将searchDelay: N 设置为足够大以捕获您所有输入的内容,但是一旦您让它在菜单中返回增量结果,BAM 您继续输入的能力并可能最终在单词的其他地方匹配走出窗外。

我真正想要的是在 shell 或像样的文本编辑器(例如 fzf)中完成的类似模糊查找器的功能。这样的查找器会跳过中间字符,基本上按字符拆分您的输入并在它们之间添加隐式通配符。您继续输入,直到第一个匹配项是您想要的,然后结束查找器并让它替换值。

我开始想办法实现这一点,但并没有走得太远。我曾想过劫持_patternToRegExp(),但很快发现我的商店(带有一些JSON 数据的dojo/data/ItemFileReadStore 实例)设置了_oldAPI 标志和that never gets executed。我很高兴更新商店,但对我来说,这并不明显会使这更容易。对我的商店进行黑客攻击后,事情变得一发不可收拾,我决定采取一种涉及更少但更黑客的方法。

如果您关闭自动完成并设置选项以在单词中间进行匹配,您会得到一个非常接近所需内容的结果列表。用户剩下要做的就是在他们输入足够的输入以获得匹配项之后以及在他们 Tab 离开之前点击一次Down。那么问题就变成了如何避免需要这种人工干预并变得更加宽容。

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 数据集中的值之一。同时,我希望输入选项比从头开始输入值或手动选择匹配项要简单得多。

【问题讨论】:

  • 您使用的是什么版本的 Dojo? dojo/store/Memory 是您的选择,而不是 dojo/data/ItemFileReadStore?它可能会在数据过滤端为您提供更多选择/灵活性......
  • @KenFranqueiro 我已使用该信息更新了问题,但我使用的是 Dojo 1.10,如果这有助于解决此问题,我很乐意使用不同的商店。我正在从数据库中动态生成 JSON 数据,但它不是很多数据,如果只有 UI 小部件最终更宽容,我可以将其转换为最有效的任何格式!
  • @KenFranqueiro 自从之前回复以来,我想从其他小部件访问这些数据,并且能够使用dstore/legacy/DstoreAdapter 将商店转换为dstore/RequestMemory 以使其与dijit/FilteringSelect 兼容。不确定这是否会使 this 问题变得更容易,但确实是这样。
  • 不确定您要做什么,但 _patternToRegExp 只是 *? 的简单通配符替换,它会在其周围放置锚点。它实际上很危险,因为它不考虑文字元字符。

标签: javascript regex dojo fuzzy-search dijit.form


【解决方案1】:

也许是您的 onBlur 的解决方法/解决方案:

设置 queryExpr="\${0}" 没有延迟和自动完成关闭

在过滤选择的 onkeyup 上,您将弹出匹配项中的第一个值存储在某处,然后在 onblur 之后将过滤选择的显示值/值更改为第一个弹出窗口中的值(如果找到并匹配...)

从弹出窗口中获取第一个值:

第一个显示的值可以在一个

中找到
  • 元素 id = YOUR_FILTERING_SELECT_ID + "_popup0"

    所以如果你的 id = "mySearchData" 然后寻找 id "mySearchData_popup0"

    如果该元素存在,则将 innerHTML 存储在某处(隐藏元素或 var ...)

    将 innerHTML 中的值调整为与 store 中的值匹配:

    根据您从 innerHTML 获得的值,从中删除 span 元素,使其与您的数据存储区的值之一匹配

    如果您的 id 来自您的 filteringselect = "mySearchField" 并且您正在搜索“123”并且弹出窗口中的第一个匹配项显示“test 123 number” 那么第一个弹出窗口中的 innerHTML 值将如下所示

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

    所以,一点点字符串涂鸦(只需从 innerHTML 值中删除 span 标签),您将获得一个与 onblur 之后的第一个结果相匹配的值。

  • 【讨论】:

    • 非常感谢您的建议!结果并不完美,但这确实让我成为了其中的一部分。我implemented this a little bit differently than you suggested 但基本思想是一样的:捕捉模糊事件并使用弹出窗口中的第一项。我确信这段代码可以改进,但我找不到比emit('click') 更简洁的方式来set('value');。标签值本身实际上并不是我商店中的值,所以我不能只解析它。
    猜你喜欢
    • 2016-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-09
    • 1970-01-01
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    相关资源
    最近更新 更多