【问题标题】:Does jquery UI Autocomplete support restrict typing on invalid values where supporting multiple values?jquery UI Autocomplete 是否支持在支持多个值的情况下限制输入无效值?
【发布时间】:2013-06-12 14:10:12
【问题描述】:

我正在接管一个新网站,它使用的是n old deprecated version of the jquery autocomplete plugin。我正在尝试使用 the latest jquery ui autocomplete 重新创建功能,但有一个功能我似乎无法复制。

我正在尝试在 where there are multiple values allows 的情况下复制“mustMatch”功能。

所以基本上,如果我开始输入任何未出现在任何搜索结果中的测试(甚至是部分字符串搜索),它会重置该字段的条目(而不是让我输入不在有效选择列表)

假设我的列表(本地)是{“Bird”、“Song”、“Happy”}

它会让我输入

 Bird, Son

但如果我输入 z 之后它会保持打开状态

    Bird, Son

让我知道这是一个无效条目

这可以在 jquery ui 自动完成中做到吗?

我看到很多来自谷歌的旧帖子都在问类似的问题and answers like this one,但似乎没有一个适用于多个值(而且许多似乎根本不起作用:()

【问题讨论】:

  • 有趣的问题,慷慨的赏金..我很快就会抽出一些时间来解决它:)..没关系,我只是标记这个问题,以便我可以再次找到它..:P
  • 如果你说如果我输入了本地列表中不可用的内容,那么 api.jqueryui.com/autocomplete/#event-response 在这个事件中你可以得到你的结果出现在参数中......基于那个设置的标志并显示验证文本框上的消息或视觉内容..你想要吗?
  • leora,既然我得到了赏金,也许我问这个很傻,但是为什么@roasted 得到了支票而我得到了赏金?如果他的答案对你更好,给他赏金。
  • @Daniel - 归根结底,两种解决方案都有效。 .他先回答,所以我给了他支票。 .你付出了很多努力,坦率地说,他的代表比他少得多,所以想承认你为鼓励未来参与所做的努力,因为你的响应速度很快
  • @leora 看起来很公平,谢谢 ;)

标签: jquery jquery-ui jquery-autocomplete jquery-ui-autocomplete


【解决方案1】:

你可以使用这种sn-p:

{ 我在这里使用 keyup 事件来检查,但是在现代浏览器上,您可以使用 input (oninput) 事件来代替或绑定 onpaste 事件}

http://jsfiddle.net/q2SSF/

 var availableTags = [
     "Bird",
     "Son",
     "Happy"];

 function split(val) {
     return val.split(/,\s*/);
 }

 function checkAvailable(term) {
     var length = term.length,
         chck = false,
         term = term.toLowerCase();
     for (var i = 0, z = availableTags.length; i < z; i++)
     if (availableTags[i].substring(0, length).toLowerCase() === term) return true;


     return false;
 }

 function extractLast(term) {
     return split(term).pop();
 }

 var $autocomplete = $("#autocomplete")
 // don't navigate away from the field on tab when selecting an item
 .on("keydown", function (event) {
     if (event.keyCode === $.ui.keyCode.TAB && $(this).data("ui-autocomplete").menu.active) {
         event.preventDefault();
     }
 })
     .on("keyup", function (event) {
     var ac_value = this.value;
     if (!checkAvailable(extractLast(ac_value))) this.value = ac_value.substring(0, ac_value.length - 1);
 })
     .autocomplete({
     minLength: 0,
     source: function (request, response) {
         // delegate back to autocomplete, but extract the last term
         response($.ui.autocomplete.filter(
         availableTags, extractLast(request.term)));
     },
     focus: function () {
         // prevent value inserted on focus
         return false;
     },
     select: function (event, ui) {
         var terms = split(this.value);
         // remove the current input
         terms.pop();
         // add the selected item
         terms.push(ui.item.value);
         // add placeholder to get the comma-and-space at the end
         terms.push("");
         this.value = terms.join(", ");
         return false;
     }
 });

【讨论】:

    【解决方案2】:

    我主要是从jQuery UI multi-select example 复制过来的,但做了一些更改。目标是完全按照您描述的方式工作,并且可以处理任何输入方法:附加到字符串、插入字符串以及复制和粘贴。

    这两个键修改多示例以满足您的需要,其中创建自定义过滤器和添加到源方法。最初我更改了搜索方法,但来源让我可以更好地控制如何显示选择(实现最小长度并在最后一个词被修剪后继续显示)。

    当执行源方法时,似乎在所有输入类型(键入、粘贴、剪切)期间都会触发,我拆分输入并检查 每个 输入的有效性。我检查每一个,因为如果有人粘贴文本,那么中间的某些内容可能会在之前有效的地方变得无效。最后一个术语之前的任何内容都应用了确切的过滤器,而最后一个元素应用了从开始过滤器。最后一项的处理方式也不同,因为它被修剪到出现不匹配输入的点。

    之后,如果发生任何更改,我会更新输入值。然后我显示对 lastTerm 的响应,同时考虑到 minLength 值,即使是原始的多示例也忘记了。

    我相信我的解决方案是最好的,因为它可以处理所有输入方法,而且很简单,因为它只添加了原始示例中的一个函数。一个缺点是,为了保持解决方案的简单性而产生了一些低效率,但这些都非常轻微,不会导致任何明显的性能影响。

    其他想法:另一种想法是将拆分正则表达式更改为 /,?\s*/ 以便逗号是可选的。在我的测试中,每次响应后输入空格是很自然的。另一种方法是每次更新输入值,使逗号间距保持一致。

    jsFiddle

    var availableTags = ['Bird', 'Song', 'Happy'];
    function split(val) {
        return val.split(/,\s*/);
    }
    
    // removes the last term from the array, and adds newValue if given
    function removeLastTerm(val, newValue) {
        var terms = split(val);
        terms.pop();
        if (newValue) {
            terms.push(newValue);
        }
        terms.push('');
        return terms.join(', ');;
    }
    
    // filter from start position from:
    // http://blog.miroslavpopovic.com/jqueryui-autocomplete-filter-words-starting-with-term
    function filterFromStart(array, term) {
        var matcher = new RegExp('^' + $.ui.autocomplete.escapeRegex(term), 'i');
        return $.grep(array, function (value) {
            return matcher.test(value.label || value.value || value);
        });
    }
    function filterExact(array, term) {
        var matcher = new RegExp('^' + $.ui.autocomplete.escapeRegex(term) + '$', 'i');
        return $.grep(array, function (value) {
            return matcher.test(value.label || value.value || value);
        });
    }
    $('#tags')
    // don't navigate away from the field on tab when selecting an item
    .bind('keydown', function (event) {
        if (event.keyCode === $.ui.keyCode.TAB &&
        $(this).data('ui-autocomplete').menu.active) {
            event.preventDefault();
        }
    })
    .autocomplete({
        minLength: 0,
        delay: 0,
        source: function (request, response) {
            var terms = split(request.term),
                lastTrimmed = false,
                lastTerm,
                originalMaxIndex = terms.length - 1,
                filteredMaxIndex;
    
            if (originalMaxIndex >= 0) {
                // remove any terms that don't match exactly
                for (var i = originalMaxIndex - 1; i >= 0; i--) {
                    if (filterExact(availableTags, terms[i]).length == 0) {
                        terms.splice(i, 1);
                    }
                }
    
                filteredMaxIndex = terms.length - 1;
                // trim the last term until it matches something or is emty
                lastTerm = terms[filteredMaxIndex];
                while (lastTerm.length != 0 &&
                    filterFromStart(availableTags, lastTerm).length == 0) {
                    lastTerm = lastTerm.substr(0, lastTerm.length - 1);
                    lastTrimmed = true;
                }
    
                if (lastTrimmed) {
                    // add modified LastTerm or reduce terms array
                    if (lastTerm.length == 0) {
                        terms.splice(filteredMaxIndex--, 1);
                        terms.push('');
                    }
                    else terms[filteredMaxIndex] = lastTerm;
                }
    
                if (filteredMaxIndex >= 0) {
                    // only execute if we've removed something
                    if (filteredMaxIndex < originalMaxIndex || lastTrimmed) {
                        this.element.val(terms.join(', '));
                    }
                } else {
                    this.element.val(request.term);
                }
    
                if (this.options.minLength <= lastTerm.length) {
                    response(filterFromStart(availableTags, lastTerm));
                }
                else {
                    response([]);
                }
            }
            else {
                response(filterFromStart(availableTags, ''));
            }
    
        },
        focus: function () {
            // prevent value inserted on focus
            return false;
        },
        select: function (event, ui) {
            // add the selected value to the input.
            this.value = removeLastTerm(this.value, ui.item.value);
            return false;
        }
    });
    

    【讨论】:

    • Giminez - 我稍微更新了问题,以更多地关注限制输入(而不是将值重置为“”,这对用户来说似乎是一种“更好”和更直观的体验。你能想到一个调整您的答案以支持该行为的方法。我给了 +1,而您当时确实给出了有效的答案
    • @我正在测试两个答案。我注意到的一件事是,另一个答案似乎限制得更快..在我输入一个“坏”字母后,它会恢复它,我似乎可以在这个字母上输入多个字母,并且似乎有一个在恢复错误条目之前稍有延迟。
    • 我将延迟设置为 0,这大大降低了效果,但并不完全。我的解决方案与其他解决方案的区别在于我们在哪里进行检查。我可以像其他一样检查输入事件,但我喜欢我的解决方案的简单性,将所有更改都限制在一个函数中。 IMO,延迟更改可以接受额外的字符。
    猜你喜欢
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2020-06-23
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多