Google地图API API自动完成 – 在input时select第一个选项

根据http://code.google.com/intl/sk-SK/apis/maps/documentation/javascript/places.html#places_autocomplete,我已成功在自己的input框中实现了Google地图位置V3自动完成function。 它很好地工作,但我很想知道如何使用户按下input时,从build议中select第一个选项。 我想我会需要一些JS的魔力,但我是非常新的JS,不知道从哪里开始。

提前致谢!

在我最近工作的网站上实现自动完成function时,我遇到了同样的问题。 这是我提出的解决scheme:

$("input").focusin(function () { $(document).keypress(function (e) { if (e.which == 13) { var firstResult = $(".pac-container .pac-item:first").text(); var geocoder = new google.maps.Geocoder(); geocoder.geocode({"address":firstResult }, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { var lat = results[0].geometry.location.lat(), lng = results[0].geometry.location.lng(), placeName = results[0].address_components[0].long_name, latlng = new google.maps.LatLng(lat, lng); $(".pac-container .pac-item:first").addClass("pac-selected"); $(".pac-container").css("display","none"); $("#searchTextField").val(firstResult); $(".pac-container").css("visibility","hidden"); moveMarker(placeName, latlng); } }); } else { $(".pac-container").css("visibility","visible"); } }); }); 

http://jsfiddle.net/dodger/pbbhH/

这是一个解决scheme,不会产生可能返回错误结果的地理编码请求: http : //jsfiddle.net/amirnissim/2D6HW/

当用户点击自动填充字段时,它会模拟down-arrow按键。 事件在返回事件之前触发,因此它模拟用户使用键盘select第一个build议。

这里是代码(在Chrome和Firefox上testing):

 <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script> <script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script> <script> var pac_input = document.getElementById('searchTextField'); (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 && !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); </script> 

这是一个真正的,非hacky解决scheme的例子。 它不会使用任何浏览器黑客等,只是从谷歌提供的公共API的方法,并在这里logging: 谷歌地图API

唯一的缺点是,如果用户没有从列表中select一个项目,则需要额外的Google请求。 好处是结果总是正确的,因为查询与自动完成中的查询完全相同。 第二个好处是,只使用公共API方法,而不依赖于AutoComplete小部件的内部HTML结构,如果Google做出改变,我们可以肯定我们的产品不会中断。

 var input = /** @type {HTMLInputElement} */(document.getElementById('searchTextField')); var autocomplete = new google.maps.places.Autocomplete(input); // These are my options for the AutoComplete autocomplete.setTypes(['(cities)']); autocomplete.setComponentRestrictions({'country': 'es'}); google.maps.event.addListener(autocomplete, 'place_changed', function() { result = autocomplete.getPlace(); if(typeof result.address_components == 'undefined') { // The user pressed enter in the input // without selecting a result from the list // Let's get the list from the Google API so that // we can retrieve the details about the first result // and use it (just as if the user had actually selected it) autocompleteService = new google.maps.places.AutocompleteService(); autocompleteService.getPlacePredictions( { 'input': result.name, 'offset': result.name.length, // I repeat the options for my AutoComplete here to get // the same results from this query as I got in the // AutoComplete widget 'componentRestrictions': {'country': 'es'}, 'types': ['(cities)'] }, function listentoresult(list, status) { if(list == null || list.length == 0) { // There are no suggestions available. // The user saw an empty list and hit enter. console.log("No results"); } else { // Here's the first result that the user saw // in the list. We can use it and it'll be just // as if the user actually selected it // themselves. But first we need to get its details // to receive the result on the same format as we // do in the AutoComplete. placesService = new google.maps.places.PlacesService(document.getElementById('placesAttribution')); placesService.getDetails( {'reference': list[0].reference}, function detailsresult(detailsResult, placesServiceStatus) { // Here's the first result in the AutoComplete with the exact // same data format as you get from the AutoComplete. console.log("We selected the first item from the list automatically because the user didn't select anything"); console.log(detailsResult); } ); } } ); } else { // The user selected a result from the list, we can // proceed and use it right away console.log("User selected an item from the list"); console.log(result); } }); 

看来有一个更好的和干净的解决scheme:要使用google.maps.places.SearchBox而不是google.maps.places.Autocomplete 。 代码几乎是一样的,只是从多个地方获得第一个。 在按Enter键时,返回正确的列表 – 所以它运行开箱,并且不需要黑客。

请参阅示例HTML页面:

http://rawgithub.com/klokan/8408394/raw/5ab795fb36c67ad73c215269f61c7648633ae53e/places-enter-first-item.html

相关的代码片段是:

 var searchBox = new google.maps.places.SearchBox(document.getElementById('searchinput')); google.maps.event.addListener(searchBox, 'places_changed', function() { var place = searchBox.getPlaces()[0]; if (!place.geometry) return; if (place.geometry.viewport) { map.fitBounds(place.geometry.viewport); } else { map.setCenter(place.geometry.location); map.setZoom(16); } }); 

该示例的完整源代码位于: https : //gist.github.com/klokan/8408394

对于Google商家信息自动完成V3,最好的解决scheme是两个API请求。

这是小提琴

之所以没有其他的答案是足够的,是因为他们要么使用jQuery来模仿事件(hacky),要么使用地理编码器或Google地方search框不总是匹配自动完成的结果 。 相反,我们要做的就是使用谷歌的自动完成服务,这里只详细介绍了javascript(没有jquery)

下面详细介绍了使用本机Google API生成自动填充框的最多的跨浏览器兼容解决scheme,然后重新运行查询以select第一个选项。

 <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=places&language=en"></script> 

使用Javascript

 // For convenience, although if you are supporting IE8 and below // bind() is not supported var $ = document.querySelector.bind(document); function autoCallback(predictions, status) { // *Callback from async google places call if (status != google.maps.places.PlacesServiceStatus.OK) { // show that this address is an error pacInput.className = 'error'; return; } // Show a successful return pacInput.className = 'success'; pacInput.value = predictions[0].description; } function queryAutocomplete(input) { // *Uses Google's autocomplete service to select an address var service = new google.maps.places.AutocompleteService(); service.getPlacePredictions({ input: input, componentRestrictions: { country: 'us' } }, autoCallback); } function handleTabbingOnInput(evt) { // *Handles Tab event on delivery-location input if (evt.target.id == "pac-input") { // Remove active class evt.target.className = ''; // Check if a tab was pressed if (evt.which == 9 || evt.keyCode == 9) { queryAutocomplete(evt.target.value); } } } // ***** Initializations ***** // // initialize pac search field // var pacInput = $('#pac-input'); pacInput.focus(); // Initialize Autocomplete var options = { componentRestrictions: { country: 'us' } }; var autocomplete = new google.maps.places.Autocomplete(pacInput, options); // ***** End Initializations ***** // // ***** Event Listeners ***** // google.maps.event.addListener(autocomplete, 'place_changed', function () { var result = autocomplete.getPlace(); if (typeof result.address_components == 'undefined') { queryAutocomplete(result.name); } else { // returns native functionality and place object console.log(result.address_components); } }); // Tabbing Event Listener if (document.addEventListener) { document.addEventListener('keydown', handleTabbingOnInput, false); } else if (document.attachEvent) { // IE8 and below document.attachEvent("onsubmit", handleTabbingOnInput); } // search form listener var standardForm = $('#search-shop-form'); if (standardForm.addEventListener) { standardForm.addEventListener("submit", preventStandardForm, false); } else if (standardForm.attachEvent) { // IE8 and below standardForm.attachEvent("onsubmit", preventStandardForm); } // ***** End Event Listeners ***** // 

HTML

 <form id="search-shop-form" class="search-form" name="searchShopForm" action="/impl_custom/index/search/" method="post"> <label for="pac-input">Delivery Location</label> <input id="pac-input" type="text" placeholder="Los Angeles, Manhattan, Houston" autocomplete="off" /> <button class="search-btn btn-success" type="submit">Search</button> </form> 

唯一的抱怨是本地实现返回一个不同的数据结构,尽pipe信息是相同的。 相应地调整。

我只想为amirnissim的答案写一个小小的改进
发布的脚本不支持IE8,因为“event.which”在IE8中似乎总是空的。
要解决这个问题,你只需要另外检查“event.keyCode”:

 listener = function (event) { if (event.which == 13 || event.keyCode == 13) { var suggestion_selected = $(".pac-item.pac-selected").length > 0; if(!suggestion_selected){ var simulated_downarrow = $.Event("keydown", {keyCode:40, which:40}) orig_listener.apply(input, [simulated_downarrow]); } } orig_listener.apply(input, [event]); }; 

JS-Fiddle: http : //jsfiddle.net/QW59W/107/

这些答案似乎没有为我工作。 他们会得到一般的位置,但实际上并没有达到我search的实际位置。 在.pac-item中,你可以通过select$('。pac-item:first')来实际得到地址(不包括地方的名字)。children()[2] .textContent

所以这里是我的解决scheme:

 $("#search_field").on("keyup", function(e) { if(e.keyCode == 13) { searchPlaces(); } }); function searchPlaces() { var $firstResult = $('.pac-item:first').children(); var placeName = $firstResult[1].textContent; var placeAddress = $firstResult[2].textContent; $("#search_field").val(placeName + ", " + placeAddress); var geocoder = new google.maps.Geocoder(); geocoder.geocode({"address":placeAddress }, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { var lat = results[0].geometry.location.lat(), lng = results[0].geometry.location.lng(), placeName = results[0].address_components[0].long_name, latlng = new google.maps.LatLng(lat, lng); map.panTo(latlng); } }); } 

我知道这个问题已经得到了答复,但是我认为我会抛出2美分,以防其他人遇到和我一样的问题。

@benregn @amirnissim我认为select错误来自:

 var suggestion_selected = $(".pac-item.pac-selected").length > 0; 

pac-selected类应该是pac-item-selected ,这就解释了为什么!suggestion_selected总是评估为true,导致在使用'keyup'或'keydown'来突出显示所需位置后按下回车键时会select错误的位置。

这个怎么样?

 $("input").keypress(function(event){ if(event.keyCode == 13 || event.keyCode == 9) { $(event.target).blur(); if($(".pac-container .pac-item:first span:eq(3)").text() == "") firstValue = $(".pac-container .pac-item:first .pac-item-query").text(); else firstValue = $(".pac-container .pac-item:first .pac-item-query").text() + ", " + $(".pac-container .pac-item:first span:eq(3)").text(); event.target.value = firstValue; } else return true; }); 

我做了一些这方面的工作,现在我可以强制使用angular度js和angular度自动完成模块谷歌广场select第一选项。
感谢kuhnza
我的代码

 <form method="get" ng-app="StarterApp" ng-controller="AppCtrl" action="searchresults.html" id="target" autocomplete="off"> <br/> <div class="row"> <div class="col-md-4"><input class="form-control" tabindex="1" autofocus g-places-autocomplete force-selection="true" ng-model="user.fromPlace" placeholder="From Place" autocomplete="off" required> </div> <div class="col-md-4"><input class="form-control" tabindex="2" g-places-autocomplete force-selection="true" placeholder="To Place" autocomplete="off" ng-model="user.toPlace" required> </div> <div class="col-md-4"> <input class="btn btn-primary" type="submit" value="submit"></div></div><br /><br/> <input class="form-control" style="width:40%" type="text" name="sourceAddressLat" placeholder="From Place Lat" id="fromLat"> <input class="form-control" style="width:40%"type="text" name="sourceAddressLang" placeholder="From Place Long" id="fromLong"> <input class="form-control" style="width:40%"type="text" name="sourceAddress" placeholder="From Place City" id="fromCity"> <input class="form-control" style="width:40%"type="text" name="destinationAddressLat" placeholder="To Place Lat" id="toLat"> <input class="form-control" style="width:40%"type="text" name="destinationAddressLang" placeholder="To Place Long"id="toLong"> <input class="form-control" style="width:40%"type="text" name="destinationAddress"placeholder="To Place City" id="toCity"> </form> 

这是一个庞然大物
谢谢。

基于amimissim的回答 ,我提出了一个轻微的替代scheme,利用Google的API以跨浏览器的方式处理事件(amimissim的解决scheme在IE8中似乎不起作用)。

我也必须改变pac-item.pac-selectedpac-item-refresh.pac-selected pac-item.pac-selected ,因为它似乎结果div类已经改变。 这使得在build议工作上按下ENTER (而不是select下一个)。

 var input = document.getElementById('MyFormField'); var autocomplete = new google.maps.places.Autocomplete(input); google.maps.event.addListener(autocomplete, 'keydown', function(event) { var suggestion_selected = $(".pac-item-refesh.pac-selected").length > 0; if (event.which == 13 && !suggestion_selected) { var simulated_downarrow = $.Event("keydown", { keyCode: 40, which: 40 }); this.apply(autocomplete, [simulated_downarrow]); } this.apply(autocomplete, [event]); }); 

只是一个纯粹的JavaScript版本(没有jquery)的伟大amirnissim的解决scheme:

 listener = function(event) { var suggestion_selected = document.getElementsByClassName('.pac-item-selected').length > 0; if (event.which === 13 && !suggestion_selected) { var e = JSON.parse(JSON.stringify(event)); e.which = 40; e.keyCode = 40; orig_listener.apply(input, [e]); } orig_listener.apply(input, [event]); };