我正在使用 JavaScript Google Places 自动完成 API v3。它工作正常,但我想知道是否有一种方法可以强制从自动完成中进行选择,即不接受任何自由格式文本的输入。我查看了文档并没有看到这样的选项,但我想我会问只是为了安全。我确信我可以找到一种方法来使用一些 JavaScript,但如果它可用的话,我更愿意使用已经构建的方法。谢谢!
13 回答
实际上,我们所做的如下:
- 每次从自动完成列表中选择一个位置时,我们使用来自 JSON 响应的一些字段(城市名称、国家名称、经度和纬度)填充一些隐藏字段
- 当表单提交后,我们检查这些字段是否有值,如果没有,则表示用户没有从列表中选择位置,而是自己输入了一个值。
它不是以 JS 方式解决问题,但它仍然可以很好地解决问题!
<script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"
type="text/javascript"></script>
<script>
var IsplaceChange = false;
$(document).ready(function () {
var input = document.getElementById('txtlocation');
var autocomplete = new google.maps.places.Autocomplete(input, { types: ['(cities)'] });
google.maps.event.addListener(autocomplete, 'place_changed', function () {
var place = autocomplete.getPlace();
IsplaceChange = true;
});
$("#txtlocation").keydown(function () {
IsplaceChange = false;
});
$("#btnsubmit").click(function () {
if (IsplaceChange == false) {
$("#txtlocation").val('');
alert("please Enter valid location");
}
else {
alert($("#txtlocation").val());
}
});
});
</script>
Google Places API 当前不支持此功能。如果您认为这是一项有用的功能,请提交Places API - 功能请求。
以下解决方案对我有用(使用 jQuery)。这个想法是blur()
一旦输入失去焦点,使用事件来强制最后选择的地址。
blur
我们添加了一个超时来防止和事件之间的冲突place_changed
。
考虑以下 html:
<input type="text" placeholder="Your address" id="autocomplete">
以及以下 javascript :
var autocomplete = new google.maps.places.Autocomplete(
(document.getElementById('autocomplete')),
{types: ['geocode']});
autocomplete.addListener('place_changed', fillInAddress);
var currentAddress = {
line_1: "",
line_2: "",
zipcode: "",
city: "",
country: "",
lat: "",
lng: "",
one_liner: ""
};
function fillInAddress() {
var place = this.autocomplete.getPlace();
// reset the address
currentAddress = {
line_1: "",
line_2: "",
zipcode: "",
city: "",
country: "",
lat: "",
lng: "",
one_liner: place.formatted_address
};
// store relevant info in currentAddress
var results = place.address_components.reduce(function(prev, current) {
prev[current.types[0]] = current['long_name'];
return prev;
}, {})
if (results.hasOwnProperty('route')) {
currentAddress.line_1 = results.route;
}
if (results.hasOwnProperty('street_number')) {
currentAddress.line_1 = results.street_number + " " + currentAddress.line_1;
}
if (results.hasOwnProperty('postal_code')) {
currentAddress.zipcode = results.postal_code;
}
if (results.hasOwnProperty('locality')) {
currentAddress.city = results.locality;
}
if (results.hasOwnProperty('country')) {
currentAddress.country = results.country;
}
currentAddress.lat = Number(place.geometry.location.lat()).toFixed(6);
currentAddress.lng = Number(place.geometry.location.lng()).toFixed(6);
}
$('#autocomplete').blur(function() {
var address = $('#autocomplete').val();
// we set a timeout to prevent conflicts between blur and place_changed events
var timeout = setTimeout(function() {
// release timeout
clearTimeout(timeout);
if (address !== currentAddress.one_liner) {
$('#autocomplete').val(currentAddress.one_liner);
}
}, 500);
});
我希望这有帮助。
var options = {
language: 'en',
types: ['(cities)'],
};
var input = document.getElementById('city');
var autocomplete = new google.maps.places.Autocomplete(input, options);
input.addEventListener("change", function(){
input.value = "";
});
输入更改时退出值对我有用。它强制使用 Google 地方信息。
我遇到了同样的问题,下面是我想出的一个解决方法。这可以与诸如 onchange 或 onkeyup 之类的事件结合使用。希望能帮助到你!
//Arguments:
address - string containing the place that you want to validate
address_success_div - div object specifically used for displaying validation
function is_location_valid(address, address_success_div)
{
var geocoder = new google.maps.Geocoder();
geocoder.geocode( {"address": address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK)
{
address_success_div.innerHTML = "SUCCESS";
}
else
{
address_success_div.innerHTML = "FAILURE";
}
});
}
我使用这里找到的代码解决了我的问题
<asp:TextBox runat="server" ID="TextBox1" />
<input type="button" id="btnSubmit" name="name" value="Validate" />
<div id="dvMap">
</div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=places&key=AIzaSyBE1J5Pe_GZXBR_x9TXOv6TU5vtCSmEPW4"></script>
<script type="text/javascript">
var isPlaceChanged = false;
google.maps.event.addDomListener(window, 'load', function () {
var places = new google.maps.places.Autocomplete(document.getElementById('<%= TextBox1.ClientID %>'));
google.maps.event.addListener(places, 'place_changed', function () {
isPlaceChanged = true;
var geocoder = new google.maps.Geocoder();
var place = places.getPlace();
var address = place.formatted_address;
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var latitude = results[0].geometry.location.lat();
var longitude = results[0].geometry.location.lng();
var mapOptions = { center: new google.maps.LatLng(latitude, longitude), zoom: 15, mapTypeId: google.maps.MapTypeId.ROADMAP };
var map = new google.maps.Map(document.getElementById("dvMap"), mapOptions);
var marker = new google.maps.Marker({ position: new google.maps.LatLng(latitude, longitude), map: map });
} else {
alert("Request failed.")
}
});
});
});
$(function () {
$("#TextBox1").keydown(function () {
isPlaceChanged = false;
});
$("#btnSubmit").click(function () {
if (!isPlaceChanged) {
$("#TextBox1").val('');
alert("Please Enter valid location");
}
else {
alert($("#TextBox1").val());
}
});
});
</script>
您可以使用输入模式标签,强制用户选择基于 Google 自动完成 API 的预定。
输入:
<form>
<input type="text" onkeyup="changePatterns()" onchange="changePatterns()" id="autocomplete" required pattern="">
<input type="submit">
</form>
JS文件:
function changePatterns() {
let input = document.getElementById('autocomplete').value;
let regExp = new RegExp(' ', 'g');
input = input.replace(regExp, '%20');
let mapsURL = 'https://maps.googleapis.com/maps/api/place/autocomplete/json'
mapsURL += '?types=geocode';
mapsURL += '&key=YOUR-KEY-HERE';
mapsURL += `&input=${input}`;
const endpoint = 'middle.php';
let formData = new FormData();
formData.append('url', mapsURL);
fetch(endpoint, {
method: 'post',
body: formData
})
.then(blob => blob.json())
.then(response => {
const predictions = response.predictions;
let {length} = predictions;
let pattern = '';
for(let i = 0; i < length; i++){
pattern += i == 0 ? '' : '|';
pattern += predictions[i].description
}
const input = document.getElementById('autocomplete');
input.setAttribute('pattern', pattern);
});
}
由于 CORS 政策的问题,我不得不使用 php 中间体:
<?php
header('Content-Type: application/json');
$url = $_POST['url'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //remove on upload
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, false);
curl_setopt($ch, CURLOPT_REFERER, "https://www.notmydomain.com");
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$result = curl_exec($ch);
echo curl_error($ch);
curl_close($ch);
echo $result;
就像他们提到的那样,Google Autocomplete API不支持它。我找到了一种方法,通过创建一个隐藏元素来存储所选位置,而不是检查它是否等于自动完成输入。
/*----------------------------------------------------*/
/* check if it's valid address
/*----------------------------------------------------*/
function checkAddress(location, validLocation) {
if (location.val() == validLocation.val()) {
return true;
}
return false;
}
/*----------------------------------------------------*/
/* initialize auto complete address
/*----------------------------------------------------*/
function initialize() {
let input = document.getElementById('autocomplete-input');
let inputHidden = document.getElementById('autocomplete-input-hidden');
let options = {
types: ['(regions)'],
componentRestrictions: {country: "tn"}
};
let autocomplete =new google.maps.places.Autocomplete(input, options);
autocomplete.setFields(['formatted_address']);
autocomplete.addListener('place_changed', function () {
inputHidden.value= autocomplete.getPlace().formatted_address;
});
}
在你的 main 中调用函数。
let location = $('#autocomplete-input');
let validLocation = $('#autocomplete-input-hidden');
checkAddress(location,validLocation);
在你的 html 中:
<input id="autocomplete-input" type="text">
<input id="autocomplete-input-hidden" type="hidden" >
我找到了一个使用 jquery 验证插件实现的更简单的解决方案,但这不是必须的。我只是使用一个类名作为标志来显示该字段是有效的(即用户从 Google 中做出的选择)还是无效的(即他们输入了自己的内容)。我创建了两个函数,一个是添加类“err”,一个是删除它。
function invalidate(element_id){
$('#' + element_id).addClass('err');
}
function makeValid(element_id){
if ($('#' + element_id).hasClass('err')){
$('#' + element_id).removeClass('err');
}
$('#' + element_id).valid(); //this is a method from jquery validation plugin to check validity of a field
}
然后,onkeydown 我调用了“invalidate”函数来标记输入元素已被输入。
document.getElementById("element_id").setAttribute('onkeydown', "invalidate('element_id')");
在 Google 自动完成 API 的末尾(我在 fillInAddress 方法的末尾做了),我调用了“makeValid”来删除标志,因为用户刚刚从下拉菜单中选择了一个选项。
makeValid(userElementId);
最后,我验证了当用户键入而不是选择选项时用作标志的“err”类不存在。在这里,我使用了 jquery 验证插件,但如果需要,您可以使用其他东西。
jQuery.validator.addMethod("hasClassErr", function(value, element) {
return this.optional( element ) || !element.classList.contains("err");
}, jQuery.validator.format("Please choose an option from the dropdown menu."));
FORM_RULES = {
element_name: {required: true, 'hasClassErr': true}
};
$('#form_id').validate({
rules: FORM_RULES
});
见https://stackoverflow.com/a/52534805/4481226
下面不起作用。留作历史
一种更简单的方法可能是:
let placeInputEl = document.getElementById("placeInput");
let autcomplete = new google.maps.places.Autocomplete(placeInputEl);
placeInputEl.addEventListener("change", () => {
//this fires when the user changes to a non-selection / freeform text
doStuff(true);
});
autocomplete.addListener("place_changed", () => {
//this fires when the user selects a place from Google
doStuff(false);
});
function doStuff(isFreeText) {
//maybe clear the selection or do whatever you need to reset
if (isFreeText) {
placeInputEl.value = "";
return;
}
// handle a place selection
}
<input id="placeInput" />
这使您可以清除输入、确定验证、重置输入或您想要执行的任何强制选择操作。
该place_changed
事件仅在用户选择输入或按 Enter 时触发。
该change
事件之前触发,place_changed
因此您可以应用您的逻辑而不会干扰谷歌的 api 调用
嗨,我设法通过在每次用户关注输入字段时创建自动完成对象并在每次模糊时检查它的值来做到这一点:
var autocompleteField;
var input = document.getElementById('YOUR_INPUT');
$('#YOUR_INPUT').focus(function(e){
if(autocompleteField){
autocompleteField=null;
}
autocompleteField = new google.maps.places.Autocomplete(input);
});
$('#YOUR_INPUT').blur(function(e){
var results = autocompleteField.getPlace();
if(!results){
$(this).attr('value','');
}
});
我从这里结合了几个不同答案的建议解决了这个问题。用户输入地址的我的文本字段称为 txtPlaces。这是我的代码:
var pac_input = document.getElementById('txtPlaces');
(function pacSelectFirst(input) {
// store the original event binding function
var _addEventListener = (input.addEventListener) ? input.addEventListener : input.attachEvent;
function addEventListenerWrapper(type, listener) {
// Simulate a 'down arrow' keypress on hitting 'return' when no pac suggestion is selected,
// and then trigger the original listener.
if (type == "keydown") {
var orig_listener = listener;
listener = function(event) {
var suggestion_selected = $(".pac-item-selected").length > 0;
if ((event.which == 13 || event.which == 9) && !suggestion_selected) {
var simulated_downarrow = $.Event("keydown", {
keyCode: 40,
which: 40
});
orig_listener.apply(input, [simulated_downarrow]);
}
orig_listener.apply(input, [event]);
};
}
_addEventListener.apply(input, [type, listener]);
}
input.addEventListener = addEventListenerWrapper;
input.attachEvent = addEventListenerWrapper;
var autocomplete = new google.maps.places.Autocomplete(input);
})(pac_input);
$('#txtPlaces').blur(function(e){
selectFirstAddress(pac_input);
});
////Ensuring that only Google Maps adresses are inputted
function selectFirstAddress (input) {
google.maps.event.trigger(input, 'keydown', {keyCode:40});
google.maps.event.trigger(input, 'keydown', {keyCode:13});
}
这将正确响应 Enter 或 Tab 键,以及当用户选择另一个字段时。希望这可以帮助!