jquery UI自动完成支持是否限制在支持多个值的无效值上键入?

时间:2013-06-16 13:10:01

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

我正在接管一个新网站,它正在使用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,但似乎没有一个与多个值一起工作(许多似乎根本不起作用:()

2 个答案:

答案 0 :(得分:6)

你可以使用这种代码段:

{我在这里使用keyup事件进行检查,但在现代浏览器中,您可以使用输入(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;
     }
 });

答案 1 :(得分:3)

我主要是从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;
    }
});