谷歌自动完成 - 输入以选择

100

我已经为HTML表单中的文本字段设置了Google Autocomplete,它完美地运作着。

然而,在建议列表出现时,如果您使用箭头进行滚动并使用enter进行选择,则会提交表单,尽管仍有需要填写的框。如果单击以选择建议,则可以正常工作,但按下 enter 会提交表单。

我该如何控制这个? 如何停止enter提交表单,而是选择自动完成的建议?

谢谢!{S}

10个回答

122

当按下回车键时,您可以使用preventDefault阻止表单被提交,我通常会这样使用:

  var input = document.getElementById('inputId');
  google.maps.event.addDomListener(input, 'keydown', function(event) { 
    if (event.keyCode === 13) { 
        event.preventDefault(); 
    }
  }); 

3
这将始终取消输入框中的提交。我只需要在用户按回车键选择自动完成选项时取消提交。 - A. Matías Quezada
1
运行得非常好。从列表中选择自动完成选项并按回车键不再提交表单。 - Eric L.
这更像是一种反模式,而不是解决方案。就像使用onClick处理程序提交表单而不是onSubmit处理程序一样。按下Enter键应该提交表单。 - Alex Fedoseev
4
我过去半个小时一直在使用 keyup 来解决我的问题,而你成功了。因此,各位,不要使用 keyup 来捕捉表单提交。 - Nico
如何移除DOM监听器? - Ricky Boyce
1
为什么要使用 google.maps.event.addDomListener(input, ...) 而不是 input.addEventListener(...) - tvanc

58

使用Google事件处理似乎是正确的解决方案,但对我来说并不起作用。这个jQuery解决方案对我有效:

$('#inputId').keydown(function (e) {
  if (e.which == 13 && $('.pac-container:visible').length) return false;
});

.pac-container是包含自动完成匹配项的div元素。它的设计理念是当匹配项可见时,按Enter键将选择活动匹配项。但是当匹配项被隐藏时(即地点已被选择),按Enter键将提交表单。


1
工作得非常好,谢谢。简单而有效。 - luke_mclachlan
1
可能是最优雅的解决方案。谢谢! - Nikolay Traykov
但这样不会允许在选择地址之前提交空字段的输入吗? - amosmos
1
这在Chrome中不起作用。看起来Chrome键事件无法检测到Enter,如果输入框位于表单内。 - Bruno
1
这种解决方案的唯一缺点是,如果Google决定更改他们注入到您的页面中的HTML并将.pac-container重命名为其他内容,则会出现问题。 - Justin Tanner

22
我将@sren和@mmalone的前两个答案合并,产生了以下内容:
var input= document.getElementById('inputId');
google.maps.event.addDomListener(input, 'keydown', function(e) { 
    if (e.keyCode == 13 && $('.pac-container:visible').length) { 
        e.preventDefault(); 
    }
}); 

该功能在页面上运行得非常好。当建议容器(.pac-container)可见时,可以防止表单被提交。因此,当用户按下回车键选择自动完成下拉列表中的选项时,必须再次按下回车键才能提交表单。

我使用这个解决方法的主要原因是,如果在选择选项后立即通过回车键发送表单,纬度和经度值将无法快速传递到它们的隐藏表单元素中。

所有的功劳归原作者所有。


10

这个方法对我有用:

google.maps.event.addDomListener(input, 'keydown', e => {

  // If it's Enter
  if (e.keyCode === 13) {

    // Select all Google's dropdown DOM nodes (can be multiple)
    const googleDOMNodes = document.getElementsByClassName('pac-container');

    // Check if any of them are visible (using ES6 here for conciseness)
    const googleDOMNodeIsVisible = (
      Array.from(googleDOMNodes).some(node => node.offsetParent !== null)
    );

    // If one is visible - preventDefault
    if (googleDOMNodeIsVisible) e.preventDefault();

  }

});

能够轻松地从ES6转换为任何符合浏览器规范的代码。


我喜欢你的答案,但是我不得不稍微调整一下才能让它正常工作。我已经发布了我的解决方案。 - schulwitz

4
我对@sren的回答有问题,因为它总是阻止提交事件。我喜欢@mmalone的回答,但它的行为是随机的,有时当我按下ENTER选择位置时,处理程序在容器隐藏后才运行。因此,这就是我最终做的事情。

var location_being_changed,
    input = document.getElementById("js-my-input"),
    autocomplete = new google.maps.places.Autocomplete(input),
    onPlaceChange = function () {
        location_being_changed = false;
    };

google.maps.event.addListener( this.autocomplete,
                               'place_changed',
                               onPlaceChange );

google.maps.event.addDomListener(input, 'keydown', function (e) {
    if (e.keyCode === 13) {
        if (location_being_changed) {
            e.preventDefault();
            e.stopPropagation();
        }
    } else {
        // means the user is probably typing
        location_being_changed = true;
    }
});

// Form Submit Handler
$('.js-my-form').on('submit', function (e) {
    e.preventDefault();
    $('.js-display').text("Yay form got submitted");
});
<p class="js-display"></p>
<form class="js-my-form">
    <input type="text" id="js-my-input" />
    <button type="submit">Submit</button>
</form>

<!-- External Libraries -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>

该标志确保如果位置正在更改并且用户按下回车键,事件将被阻止。最终,该标志由Google地图的place_changed事件设置为false,然后允许在按下回车键时提交表单。


这段代码对我来说确实起作用了,感谢你的努力! - Aimal Khan
此代码避免了在用户输入、按下回车键,然后按下向下箭头(或任何不触发自动完成的键)时提交。之后,返回被阻止。 - Natxet

1
你可以用原生方式做到这一点:
element.addEventListener('keydown', function(e) {
    const gPlaceChoices = document.querySelector('.pac-container')
    // No choices element ? 
    if (null === gPlaceChoices) {
        return
    }
    // Get choices visivility
    let visibility = window.getComputedStyle(gPlaceChoices).display
    // In this case, enter key will do nothing
    if ('none' !== visibility && e.keyCode === 13) {
        e.preventDefault();
     }
 })

我认为这个答案的代码最清晰,因为使用了getComputedStyle。谢谢! - fjsj
可以举一个元素作为例子。 - Greggory Wiley

1
这是一段对我很有用的简单代码(不使用jQuery)。
const googleAutcompleteField = this.renderer.selectRootElement(this.elem.nativeElement);
this.selectOnEnter(googleAutcompleteField);

这段代码是为了实现谷歌地图自动完成功能(包括或不包括此问题中所需的回车键功能)。
this.autocomplete = new google.maps.places.Autocomplete(googleAutcompleteField, this.googleMapsOptions);
this.autocomplete.setFields(['address_component', 'formatted_address', 'geometry']);
this.autocomplete.addListener('place_changed', () => {
  this.zone.run(() => {
    this.googleMapsData.emit([this.autocomplete.getPlace()]);
  })
})

上面第一段代码中调用的selectOnEnter被定义为:

selectOnEnter(inputField) {
  inputField.addEventListener("keydown", (event) => {
    const selectedItem = document.getElementsByClassName('pac-item-selected');
    if (event.key == "Enter" && selectedItem.length != 0) {
      event.preventDefault();
    }
  })
}

该代码使谷歌地图自动完成字段选择用户使用向下箭头按键选择的任何项目。一旦用户按Enter键选择选项,将不会发生任何事情。用户必须再次按Enter键才能触发onSubmit()或其他命令。

0

我修改了Alex的代码,因为它在浏览器中出现了错误。这对我来说完美地解决了问题:

google.maps.event.addDomListener(
    document.getElementById('YOUR_ELEMENT_ID'),
    'keydown',
    function(e) {
          // If it's Enter
          if (e.keyCode === 13) {
            // Select all Google's dropdown DOM nodes (can be multiple)
            const googleDOMNodes = document.getElementsByClassName('pac-container');
            //If multiple nodes, prevent form submit.
            if (googleDOMNodes.length > 0){
                e.preventDefault();
            }
            //Remove Google's drop down elements, so that future form submit requests work.
            removeElementsByClass('pac-container');
          }
    }
);

function removeElementsByClass(className){
    var elements = document.getElementsByClassName(className);
    while(elements.length > 0){
        elements[0].parentNode.removeChild(elements[0]);
    }
}

0
$("#myinput").on("keydown", function(e) {
if (e.which == 13) {

if($(".pac-item").length>0)
        {
            $(".pac-item-selected").trigger("click");
}

}

如果要选择第一个结果,请使用$('.pac-item:first').trigger('click');


0

我尝试了上面的简短答案,但它们对我没有用,而我也不想尝试那些长答案,所以我创建了以下代码,这对我非常有效。 查看演示

假设这是您的表单:

<form action="" method="">
      <input type="text" name="place" id="google-places-searchbox" placeholder="Enter place name"><br><br>
      <input type="text" name="field-1" placeholder="Field 1"><br><br>
      <input type="text" name="field-2" placeholder="Field 2"><br><br>
      <button type="submit">Submit</button>
</form>

接下来的JavaScript代码将解决这个问题:

var placesSearchbox = $("#google-places-searchbox");

placesSearchbox.on("focus blur", function() {
    $(this).closest("form").toggleClass('prevent_submit');
});

placesSearchbox.closest("form").on("submit", function(e) {
    if (placesSearchbox.closest("form").hasClass('prevent_submit')) {
        e.preventDefault();
        return false;
    }
});

以下是完整的HTML页面代码(请注意,您需要将YOUR_API_KEY替换为您的Google API密钥):

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Prevent form submission when choosing a place from google places autocomplete searchbox</title>
</head>
<body>
  <form action="" method="">
      <input type="text" name="place" id="google-places-searchbox" placeholder="Enter place name"><br><br>
      <input type="text" name="field-1" placeholder="Field 1"><br><br>
      <input type="text" name="field-2" placeholder="Field 2"><br><br>
      <button type="submit">Submit</button>
  </form>

  <!-- jQuery -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

  <!-- Google Maps -->
  <!-- Note that you need to replace the next YOUR_API_KEY with your api key -->
  <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"
     async defer></script>
  <script>
    var input = document.getElementById("google-places-searchbox");
    var searchBox = new google.maps.places.SearchBox(input);

    var placesSearchbox = $("#google-places-searchbox");

    placesSearchbox.on("focus blur", function() {
        $(this).closest("form").toggleClass('prevent_submit');
    });

    placesSearchbox.closest("form").on("submit", function(e) {
        if (placesSearchbox.closest("form").hasClass('prevent_submit')) {
            e.preventDefault();
            return false;
        }
    });
  </script>
</body>
</html>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接