修改jQuery自动完成不要在Enter上急切地提交

时间:2013-09-11 19:45:32

标签: javascript jquery html jquery-ui jquery-ui-autocomplete

我们的用户抱怨说,当他们在jQuery自动完成小部件中粘贴或键入值后按Enter键时,表单就会被提交。

当他们复制粘贴自动填充选项中存在的值以及自动填充小部件打开以显示单个值时,他们非常讨厌,他们按Enter键接受该值但是在填写所有字段之前提交表单因为(by default而且我们不想更改它)小部件不会选择菜单中的第一个选项。

<form>Type C and press Enter:
    <input id="autocomplete" />
    <input type="submit" value="submit" />
</form>

$('form').submit(function () {
    alert('You submitted the form');
    return false;
});

$('#autocomplete').autocomplete({
    source: ["c#", "c", "c++", "java", "php", "coldfusion"]
});    

DEMO of the problem

我们如何更改单击Enter将仅关闭自动填充建议?

4 个答案:

答案 0 :(得分:5)

似乎jQuery UI没有留下后门来自定义开箱即用的小部件,所以你可以做的是覆盖autocomplete函数来注册onkeypress事件的回调,捕获Enter并停止传播,以便在窗口小部件打开=可见时不会提交表单。

这是怎么回事:

function cancelAutocompleteSumbission(e) {
    // Make sure this is a nodeElement and the button pressed was Enter-Return
    if (!this.nodeType || e.which != 13)
        return;

    // If the widget is visible we simply want to close the widget.
    if ($(this).autocomplete('widget').is(':visible')) {
        $(this).autocomplete('close');
        return false;
    }
}
// Making a private scope to avoid naming collision.
$.fn.autocomplete = (function () {
    // Cache the old autocomplete function.
    var oldAutocomplete = $.fn.autocomplete;

    // This will be the new autocomplete function.
    return function () {
        // If the first argument isn't "destroy" which 
        // should restore the input to it's initial state.
        if (!/^destroy$/i.test(arguments[0]))
            // Attach event to the input which will prevent Enter submission as
            // explained above.
            this.keypress(cancelAutocompleteSumbission);                
        // We need to restore the input to it's initial state,
        // detach the keypress callback.    
        else
            this.off('keypress', cancelAutocompleteSumbission);

        // Call the cached function with the give "this" scope and paramteres.
        return oldAutocomplete.apply(this, arguments);
    };
})();

Live DEMO


备注:

  • 要更改所有自动完成小部件,您需要使用jQuery的原型$.fn is an alias to $.prototype
  • 此外,您需要在使用之前更改$.fn.autocomplete,否则您所做的更改将不适用于这些小部件。
  • this函数中的
  • autocomplete实际上是一个jQuery对象,因此您不需要用$(this)
  • 包装它
  • 您可能会说,嘿,您继续为keypress事件注册回调。好吧,这正是我正在做的以及为什么我将回调写为命名函数。如果您将同一个回调传递给addEventListener,它只会注册一次。 MDNSpecifications
  • Adding code to a javascript function programmatically

答案 1 :(得分:2)

使用jQuery autocompleteautocompletecloseautocompleteopen事件,我可能会有一个更简单的解决方案。

请参阅以下代码:

var flag = 0; //global variable

$("#autocomplete").on({
    autocompleteclose: function (event, ui) {
        flag = 1;
        //set flag back to 0 with a short delay so the next keypress can submit form
        setTimeout(function () {
            flag = 0; 
        }, 100);
    },
    //if the autocomplete widget is open, don't submit form on keypress
    autocompleteopen: function (event, ui) {
        flag = 1;
    }
});

$('body').keypress(function(e) {
    if (e.keyCode == '13') {
        if (flag != 0) {
            e.preventDefault();
        } else {
            //submit form
        }
    }
});​

&#13;
&#13;
var flag = 0; //global variable

$("#autocomplete").on({
    autocompleteclose: function (event, ui) {
        flag = 1;
        //set flag back to 0 with a short delay so the next keypress can submit form
        setTimeout(function () {
            flag = 0;
        }, 100);
    },
    //if the autocomplete widget is open, don't submit form on keypress
    autocompleteopen: function (event, ui) {
        flag = 1;
    }
});

$('body').keypress(function (e) {
    if (e.keyCode == '13') {
        if (flag != 0) {
            e.preventDefault();
        } else {
            //submit form
        }
    }
});


$('form').submit(function () {
    alert('You submitted the form');
    return false;
});

$('#autocomplete').autocomplete({
    source: ["c#", "c", "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby"]
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="//code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">

<form>Type C and press Enter:
    <input id="autocomplete" />
    <input type="submit" value="submit" />
</form>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

我在某种程度上反对覆盖jqueryui实现并执行以下操作:

  • 在自动完成的关闭事件中,我在按下输入时设置了一个标志“doNotSubmit”
  • 在你的情况下,然后我将一个提交事件监听器绑定到表单,该表单检查doNotSubmit标志并相应地采取行动。

它背后的基本思想是,jqueryui的close事件在keyup或submit事件之前触发,并为你提供密钥代码。所以你可以在另一个地方(keyup,submit等)使用那个不需要的输入或其他按键。

答案 3 :(得分:0)

此问题与this one类似。虽然该页面上的解决方案很简单,但它们依赖于页面上ID的元素。我在很多页面上使用自动完成功能,因此我更喜欢gdoron的方法(在此页面上)。感谢他做了繁重的工作。

但是,我认为他的代码中存在错误。如果您转到已包含内容并键入退货的自动填充字段,则会提交表单。这是一个修复(更改是第二个&#34; if cancelAutocompleteSumbission中的块):

function cancelAutocompleteSumbission(e) {
// Make sure this is a nodeElement and the button pressed was Enter-Return
if (!this.nodeType || e.which != 13)
    return;

if (!$(this).autocomplete('widget').is(':visible') && e.which === 13){
    return false;
}

// If the widget is visible we simply want to close the widget.
if ($(this).autocomplete('widget').is(':visible')) {
    $(this).autocomplete('close');
    return false;
    }
}

// Making a private scope to avoid naming collision.
$.fn.autocomplete = (function () {
    // Cache the old autocomplete function.
    var oldAutocomplete = $.fn.autocomplete;

    // This will be the new autocomplete function.
    return function () {
        // If the first argument isn't "destroy" which
        // should restore the input to it's initial state.
        if (!/^destroy$/i.test(arguments[0]))
            // Attach event to the input which will prevent Enter submission as
            // explained above.
            this.keypress(cancelAutocompleteSumbission);
        // We need to restore the input to it's initial state,
        // detach the keypress callback.
        else
            this.off('keypress', cancelAutocompleteSumbission);

        // Call the cached function with the give "this" scope and paramteres.
        return oldAutocomplete.apply(this, arguments);
    };
})();

Live Demo