谷歌地点自动完成强制选择

31

我正在使用JavaScript 的Google地点自动完成API v3。它运行良好,但我想知道是否有一种方法可以强制从自动完成中进行选择,也就是说,输入将不接受任何自由格式的文本。我查看了文档,没有看到这样的选项,但觉得还是问一下比较保险。我相信我可以通过一些JavaScript来解决这个问题,但如果已经有可用的构建方法,我更愿意使用它。谢谢!

13个回答

17

实际上,我们所做的是以下内容:
- 每次从自动完成列表中选择一个位置时,我们会使用来自JSON响应的某些字段填充一些隐藏字段(城市名称、国家名称、经度和纬度)
- 当表单提交时,我们检查这些字段是否有值,如果没有,说明用户没有从列表中选择位置,而是自己输入了一个值。

这种方法不是以JS方式解决问题,但仍然可以很好地解决问题!


5
值得注意的是,如果用户删除了所选位置并手动输入位置,则还应从这些隐藏输入中删除值。 - digout
13
无法正常工作。假设我先从自动完成中选择正确的位置,那么基于此,您隐藏字段的值将被填充,然后如果我从自动完成框中删除一些文本并提交,则会插入错误的地址到您的数据库中,因为隐藏字段的值已经有一些值了。 - Milan

12
 <script src="http://maps.googleapis.com/maps/api/js?sensor=false&amp;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>





2
尝试添加描述或解释,以帮助人们理解这如何解决问题。 - Illidanek
如果您输入了内容并按下“Enter”键,则会触发“place_changed”事件,并返回带有单个属性名称的地点对象,该属性名称为您输入的文本。 - lcguida

10

谷歌地点API目前不支持此功能。如果您认为这将是一个有用的功能,请提交地点API-功能请求


1
我正在使用一种解决方法...相反,我使用自动完成预测API来默认选择第一个结果。 - nicolasbui
http://code.google.com/p/gmaps-api-issues/issues/detail?id=8456 如果您也受到影响,请投票。 - Anton Bessonov
1
不要这样做。这是一个可怕的想法,因为谷歌经常会出错。例如,对于新的道路,您将需要等待一年才能识别正确的地址。请参见下面的答案。 - eraoul

5
以下解决方案对我很有帮助(使用jQuery)。思路是在输入框失去焦点时使用blur()事件来强制选择最后一个选定的地址。
我们添加了一个延迟时间以防止blurplace_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);
});

我希望这能有所帮助。

这是一个不错的解决方案。由于我无法访问place.formatted_address,所以在fillInAddress函数的末尾,我只能将one_liner设置为自动完成输入字段的当前值,或者使用更复杂的方法来获取formatted_address:autocompleteObj.gm_bindings_.bounds[7].re.formattedPrediction。 - sFishman
虽然我不太倾向于使用我提出的第二个选项,因为它可能在某些情况下无法正常工作,而且相当丑陋。 - sFishman

2
    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 Places。


1
在尝试这个之前,我尝试了很多其他的解决方案,必须说,它完美地运行了。不错! - 今際のアリス

1
我遇到了同样的问题,下面是我想出来的一个解决方法。这可以与 onchange 或 onkeyup 等事件结合使用。希望能有所帮助!
// 参数: address - 包含要验证的地点的字符串 address_success_div - 用于显示验证的 div 对象
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";
        }
    });
}

1

您可以使用输入模式标签,强制用户根据Google Autocomplete 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;

0
我使用在这里找到的代码解决了我的问题。
<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>

0

查看https://dev59.com/q1wY5IYBdhLWcg3w0Kcs#52534805

以下代码不起作用,仅供参考

更简单的方法可能是:

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 事件仅在用户选择输入或按下回车键时触发。

change 事件在 place_changed 之前触发,因此您可能能够应用自己的逻辑而不会干扰谷歌的 API 调用。


0

就像他们所提到的那样,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;
 });
}

在你的主函数中调用该函数。

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

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