2

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

当他们复制粘贴自动完成选项中存在的值时,他们非常烦人,自动完成小部件打开以显示该单个值,他们按 Enter 接受该值,但随后在完成填写所有字段之前提交了表单,因为(通过默认并且我们不想更改它)小部件不会选择菜单中的第一个选项。

<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

我们如何更改单击 Enter 只会关闭自动完成建议?

4

4 回答 4

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);
    };
})();

现场演示


笔记:

  • 要更改所有自动完成小部件,您需要使用 jQuery 的原型,$.fn它是$.prototype.
  • 此外,您需要$.fn.autocomplete在使用它之前进行更改,否则您所做的更改将不适用于这些小部件。
  • this函数内部autocomplete实际上是一个 jQuery 对象,所以你不需要用$(this)
  • 你可能会说,嘿,你一直为keypress事件注册相同的回调。好吧,这正是我正在做的事情,也是我将回调编写为命名函数的原因。如果您将相同的回调传递给addEventListener它,它将只注册一次。规范_ _
  • 以编程方式将代码添加到 javascript 函数
于 2013-09-11T19:45:31.553 回答
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
        }
    }
});​

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"]
});
<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>

于 2015-09-04T00:22:06.757 回答
0

我以某种方式反对覆盖 jqueryui 实现并做了以下事情:

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

其背后的基本思想是,jqueryui 的 close 事件在 keyup 或 submit 事件之前触发,并为您提供 keycode。因此,您可以在另一个地方(keyup、submit 等)使用不需要的输入或其他按键。

于 2014-01-10T14:27:42.387 回答
0

这个问题与这个问题类似。虽然该页面上的解决方案是直截了当的,但它们取决于页面上元素的 ID。我在很多页面上都使用自动完成功能,所以我更喜欢 gdoron 的方法(在这个页面上)。感谢他承担了繁重的工作。

但是,我认为他的代码中有一个错误。如果您转到已包含内容的自动完成字段并键入返回,它将提交表单。这是一个修复(更改是 cancelAutocompleteSumbission 中的第二个“if 块”):

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);
    };
})();

现场演示

于 2014-07-27T13:29:49.270 回答