【问题标题】:Google Places Autocomplete - Pick first result on Enter key? [duplicate]Google Places Autocomplete - 在 Enter 键上选择第一个结果? [复制]
【发布时间】:2013-01-14 03:07:28
【问题描述】:

我正在使用 Google Places 自动完成功能,我只是希望它在表单字段中按下回车键并且存在建议时选择结果列表中的顶部项目。我知道以前有人问过这个问题:

Google maps Places API V3 autocomplete - select first option on enter

Google maps Places API V3 autocomplete - select first option on enter (and have it stay that way)

但这些问题的答案似乎并没有真正起作用,或者它们涉及特定的附加功能。

看起来像下面这样的东西应该可以工作(但它没有):

$("input#autocomplete").keydown(function(e) {
  if (e.which == 13) {          
    //if there are suggestions...
    if ($(".pac-container .pac-item").length) {
      //click on the first item in the list or simulate a down arrow key event
      //it does get this far, but I can't find a way to actually select the item
      $(".pac-container .pac-item:first").click();
    } else {
      //there are no suggestions
    }
  }
});

任何建议将不胜感激!

【问题讨论】:

  • 您必须使用 google.maps.places.AutocompleteService 类并手动读取 AutocompletePrediction:developers.google.com/maps/documentation/javascript/…
  • @Mubix 在您链接到的第二个问题中接受的答案涵盖了似乎需要的内容,并添加了一些可以轻松删除的额外功能。根据这个演示,我只是从上面分叉出来的:jsfiddle.net/Ut2U4/1
  • @CraigBlagg 谢谢!我最终让它工作了。不知道为什么它第一次没有工作,但是逐行重建它得到了想要的结果!
  • 太棒了。奇怪的是它没有立即工作(似乎在这里工作)。但很高兴它成功了@NChase
  • @CraigBlagg,在您的示例 (jsfiddle.net/Ut2U4/1) 中,需要确保在触发 'focusout' 时从文档中删除 'keypress' 事件(第 14 行)。否则,每次输入获得焦点时,您都​​会将其附加到文档中。

标签: javascript google-maps google-maps-api-3 google-places-api google-places


【解决方案1】:

在发现最佳答案是this one 之前,我已经阅读了这个问题的许多答案以及链接问题的答案很多次(注意:很遗憾,这不是公认的答案!)。

我修改了 2 或 3 行 将其变成一个随时可用的函数,您可以在代码中复制/粘贴该函数,并在需要时应用于许多 input 元素。这里是:

var selectFirstOnEnter = function(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]); // add the modified listener
    }
    if (input.addEventListener) { 
        input.addEventListener = addEventListenerWrapper; 
    } else if (input.attachEvent) { 
        input.attachEvent = addEventListenerWrapper; 
    }
}

用法:

selectFirstOnEnter(input1);
selectFirstOnEnter(input2);
...

【讨论】:

  • 这就像一个魅力。它需要 jQuery。如果你和我一样使用 Angular,这里有一个关于如何安装它的小指南:medium.com/@swarnakishore/…
  • 还要确保在var autocomplete = new google.maps.places.Autocomplete(input);之前调用该函数,否则它将不起作用
  • 很好的答案,非常格式化的代码。无论如何谢谢:)
  • @Derenir 已修复!
【解决方案2】:

如果您使用的是Angular 2,4, 5 & 6,请在下面的链接中找到答案

Angular 6, AGM selects first address in google autocomplete

Angular AGM autocomplete first address suggestion

【讨论】:

    【解决方案3】:

    这是解决我最简单的方法:

    autocomplete.addListener('place_changed', function() {
      if(event.keyCode == 13 || event.keyCode == 9) { // detect the enter key
        var firstValue = $(".pac-container .pac-item:first").text(); // assign to this variable the first string from the autocomplete dropdown
         }
        $('#search-address').val(firstValue); // add this string to input
        console.log(firstValue); // display the string on your browser console to check what it is
       //(...) add the rest of your code here
      });
    }
    

    【讨论】:

    • 我修改了上面的功能,它对我来说就像一个魅力。 // 使 kepdown 为 true 并选择第一个搜索结果的侦听器 this.searchElementRef.nativeElement.addEventListener('keydown', (e) => { if (e.keyCode === 13 || e.keyCode === 9) { var firstValue = $('.pac-container .pac-item:first').text(); // 如果用户没有使用箭头导航并且 this 还没有运行 this.txtValue = firstValue; google.maps .event.trigger(e.target, 'keydown', { keyCode: 40, hasRanOnce: true, }); } });
    【解决方案4】:

    监听用户是否开始使用键盘向下导航而不是每次都触发错误导航的工作解决方案

    https://codepen.io/callam/pen/RgzxZB

    这里是重要的部分

    // search input
    const searchInput = document.getElementById('js-search-input');
    
    // Google Maps autocomplete
    const autocomplete = new google.maps.places.Autocomplete(searchInput);
    
    // Has user pressed the down key to navigate autocomplete options?
    let hasDownBeenPressed = false;
    
    // Listener outside to stop nested loop returning odd results
    searchInput.addEventListener('keydown', (e) => {
        if (e.keyCode === 40) {
            hasDownBeenPressed = true;
        }
    });
    
    // GoogleMaps API custom eventlistener method
    google.maps.event.addDomListener(searchInput, 'keydown', (e) => {
    
        // Maps API e.stopPropagation();
        e.cancelBubble = true;
    
        // If enter key, or tab key
        if (e.keyCode === 13 || e.keyCode === 9) {
            // If user isn't navigating using arrows and this hasn't ran yet
            if (!hasDownBeenPressed && !e.hasRanOnce) {
                google.maps.event.trigger(e.target, 'keydown', {
                    keyCode: 40,
                    hasRanOnce: true,
                });
            }
        }
    });
    
     // Clear the input on focus, reset hasDownBeenPressed
    searchInput.addEventListener('focus', () => {
        hasDownBeenPressed = false;
        searchInput.value = '';
    });
    
    // place_changed GoogleMaps listener when we do submit
    google.maps.event.addListener(autocomplete, 'place_changed', function() {
    
        // Get the place info from the autocomplete Api
        const place = autocomplete.getPlace();
    
        //If we can find the place lets go to it
        if (typeof place.address_components !== 'undefined') {          
            // reset hasDownBeenPressed in case they don't unfocus
            hasDownBeenPressed = false;
        }
    
    });
    

    【讨论】:

    • 这似乎会导致错误TypeError: a.stopPropagation is not a function error对此有何想法?
    【解决方案5】:

    这就是我所做的并且有效:

    HTML:

    <input name="location" id="autocomplete" autocomplete="off" type="text" class="textbx" placeholder="Enter Destination" required>
    

    googleautocompletecustomized.js:

            function initialize() {
          // Create the autocomplete object, restricting the search
          // to geographical location types.
          if($('#autocomplete').length){
              autocomplete = new google.maps.places.Autocomplete(
                  (document.getElementById('autocomplete')),
                  {
                    types: ['(regions)'],
                    componentRestrictions: {country: "in"}
                  });
              google.maps.event.addListener(autocomplete, 'place_changed', function() {
                $('#autocomplete').closest('form').data('changed', true);
                fillInAddress();
              });         
          }
    
        //select first result
            $('#autocomplete').keydown(function (e) {
                if (e.keyCode == 13 || e.keyCode == 9) {
                    $(e.target).blur();
                    if($(".pac-container .pac-item:first span:eq(3)").text() == "")
                        var firstResult = $(".pac-container .pac-item:first .pac-item-query").text();
                    else
                        var firstResult = $(".pac-container .pac-item:first .pac-item-query").text() + ", " + $(".pac-container .pac-item:first span:eq(3)").text();
    
                    var geocoder = new google.maps.Geocoder();
                    geocoder.geocode({"address":firstResult }, function(results, status) {
                        if (status == google.maps.GeocoderStatus.OK) {
                            placeName = results[0];
                            e.target.value = firstResult;
                            fillInAddress(placeName);
                            $('#datetimepicker1 .input-group-addon').click();
                        }
                    });
                }
    
            });
        }
    
    // [START region_fillform]
    function fillInAddress(place) {
      // Get the place details from the autocomplete object.
      if(!place)
        var place = autocomplete.getPlace();
    
      for (var component in componentForm) {
        document.getElementById(component).value = '';
        document.getElementById(component).disabled = false;
      }
    
      // Get each component of the address from the place details
      // and fill the corresponding field on the form.
      for (var i = 0; i < place.address_components.length; i++) {
        var addressType = place.address_components[i].types[0];
        if (componentForm[addressType]) {
          var val = place.address_components[i][componentForm[addressType]];
          document.getElementById(addressType).value = val;
    
        }
      }
    
    }
    

    【讨论】:

      【解决方案6】:

      我为此做了一些工作,现在我可以使用 angular js 和 angular Autocomplete 模块从 google 地方强制选择第一个选项。
      感谢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>
      

      这是Plunker
      谢谢。

      【讨论】:

        【解决方案7】:

        我从Google maps Places API V3 autocomplete - select first option on enter转发我的答案:

        似乎有一个更好更干净的解决方案:使用google.maps.places.SearchBox 而不是google.maps.places.Autocomplete。 代码几乎相同,只是从多个地方获取第一个。按下 Enter 后,会返回正确的列表 - 因此它开箱即用,无需 hack。

        查看示例 HTML 页面:

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

        相关代码sn-p为:

        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

        【讨论】:

        • SeachBox 不允许您按(地区)或(城市)或任何类型进行过滤。
        • 我对此进行了测试,但它没有按预期工作。 SearchBox 会在您键入时执行“自动完成”请求,但当您按下回车键时,它会使用您输入的字符串在maps.googleapis.com/maps/api/js/PlaceService.QueryPlaces 发出请求。这可能会或可能不会返回实际结果。例如,通过键入“naxo”,自动完成列表作为第一个结果返回“Naxos ke Mikres Kyklades”(也许这是基于区域设置?)。按回车,不选择列表项,返回 0 个结果。
        • 搜索框太方便了。我真的希望它能让我将结果限制为地理编码或地址。
        • 但搜索框与自动完成不同。更适合“纽约的咖啡”之类的东西
        • 我已经使用 Autocomplete 大约一年了,在阅读了这篇文章并切换到 SearchBox 之后,一切都变得更好了。我有一个特殊的“getPlaceFromAutocompleteList”函数作为解决方法,但这修复了几个令人沮丧的边缘情况错误。谢谢!
        【解决方案8】:

        将输入元素放在表单元素之外。使用 javascript 填充表单。

        document.getElementById("adress").value = place.formatted_address;
        

        【讨论】:

          【解决方案9】:

          在我的站点中,为了实现同样的功能,我需要 jQuery 模拟插件 (https://github.com/jquery/jquery-simulate),然后附加事件:

          $("input#autocomplete").focusin(function () {
              $(document).keypress(function (e) {
                  if (e.which == 13) {
                      $("input#autocomplete").trigger('focus');
                      $("input#autocomplete").simulate('keydown', { keyCode: $.ui.keyCode.DOWN } ).simulate('keydown', { keyCode: $.ui.keyCode.ENTER });
                  }
              });
          });
          

          该插件会模拟按下 DOWN 然后 ENTER 键的动作,ENTER 本身不起作用,我找不到其他方法来选择第一个选项。

          希望对你有帮助

          【讨论】:

          • 这在您使用箭头键导航并按回车键选择它的情况下不起作用。
          • @dnlmzw 如果您使用箭头键导航并使用回车键选择它,那么您会触发“place_change”...
          • @user151496 是的,但如果您的字段是&lt;form&gt; 字段,则它将不起作用,那么您应该在输入时执行e.preventDefault(); (13/$.ui.keyCode.ENTER)keydown,如果您不这样做' t,请求的响应可能不会及时返回:)
          • 经过数小时的搜索和尝试破解类似解决方案后,这对我来说非常有效。
          猜你喜欢
          • 2015-10-24
          • 2016-10-01
          • 2021-11-05
          • 1970-01-01
          • 1970-01-01
          • 2020-01-20
          • 2012-10-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多