谷歌自动完成-进入选择

我已经为一个 HTML 表单的文本字段设置了 谷歌自动补全,它工作得很好。

但是,当建议列表出现时,您使用箭头滚动并使用 enter 选择,它将提交表单,尽管仍然需要填写一些框。如果你点击选择一个建议,它工作良好,但按 进来提交。

我怎么能控制这个?我如何停止输入从提交表单,而是从自动完成建议的选择?

谢谢! { S }

46873 次浏览

You can use preventDefault to stop the form being submitted when enter is hit, I used something like this:

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

Using the Google events handling seems like the proper solution but it's not working for me. This jQuery solution is working for me:

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

.pac-container is the div that holds the Autocomplete matches. The idea is that when the matches are visible, the Enter key will just choose the active match. But when the matches are hidden (i.e. a place has been chosen) it will submit the form.

The problem I had with @sren's answer was that it blocks the submit event always. I liked @mmalone's answer but it behaved randomly, as in sometimes when I hit ENTER to select the location, the handler ran after the container is hidden. So, here's what I ended up doing

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>

The flag ensures that if the location is being changed & user hits enter, the event is blocked. Eventually the flag is set to false by google map's place_changed event, which then allows the form to be submitted on hitting the enter key.

I've amalgamated the first two answers from @sren and @mmalone to produce this:

var input= document.getElementById('inputId');
google.maps.event.addDomListener(input, 'keydown', function(e) {
if (e.keyCode == 13 && $('.pac-container:visible').length) {
e.preventDefault();
}
});

works perfectly on the page. prevents the form from being submitted when the suggestion container (.pac-container) is visible. So now, an option from the autocomplete dropdown is selected when the users presses the enter key, and they have to press it again to submit the form.

My main reason for using this workaround is because I found that if the form is sent as soon as an option is selected, via the enter key, the latitude and longitude values were not being passed fast enough into their hidden form elements.

All credit to the original answers.

This one worked for me:

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


}


});

Can be easily converted from ES6 to any browser-compatible code.

I tweaked Alex's code, because it broke in the browser. This works perfect for me:

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

I've tried the above short answers but they didn't work for me, and the long answers I didn't want to try them, so I've created the following code which worked pretty well for me. See Demo

Suppose this is your form:

<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>

Then the following javascript code will solve the problem:

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

And here is how the full code looks like in the HTML page (Note that you need to replace the YOUR_API_KEY with your google api key):

<!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>

Here's a simple code that worked well for me (uses no jquery).

const googleAutcompleteField = this.renderer.selectRootElement(this.elem.nativeElement);
this.selectOnEnter(googleAutcompleteField);

This piece of code, to follow the code above, is used to implement google maps autocomplete (with or without the Enter key functionality sought in this question):

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 (called above in the first piece of code) defined:

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

This code makes the google maps autocomplete field select whichever item user selects with the down arrow keypress. Once user selects an option with a press of the Enter key, nothing happens. User has to press Enter again to trigger onSubmit() or other command

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


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


}

Use $('.pac-item:first').trigger('click'); if you want to select first result

You can do it in vanilla :

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