Автозаполнение Google - введите, чтобы выбрать

80

У меня есть Google Autocomplete, настроенный для текстового поля HTML-формы, и он отлично работает.

Однако, когда появляется список предложений, и вы используете стрелки для прокрутки и выбора с помощью ввода, он отправляет форму, хотя есть еще поля для заполнения. Если вы щелкаете, чтобы выбрать предложение, оно работает нормально, но нажатие Enter отправляет .

Как я могу это контролировать? Как я могу остановить ввод от отправки формы, а вместо этого выбрать предложение из автозаполнения?

Благодаря! {S}

кинкерсник
источник

Ответы:

110

Вы можете использовать, preventDefaultчтобы остановить отправку формы при нажатии ввода, я использовал что-то вроде этого:

  var input = document.getElementById('inputId');
  google.maps.event.addDomListener(input, 'keydown', function(event) { 
    if (event.keyCode === 13) { 
        event.preventDefault(); 
    }
  }); 
sren
источник
2
Это всегда отменит отправку из поля. Мне нужно только отменить отправку, если пользователь нажал ввод, чтобы выбрать опцию автозаполнения.
А. Матиас Кесада
1
Работает как драгоценный камень. Нажатие и выбор опции автозаполнения из списка с вводом больше не отправляет форму.
Эрик Л.
Это больше не шаблон, чем решение. То же, что и использование обработчика onClick для отправки формы вместо обработчика onSubmit. Enter должен отправить форму.
Алекс Федосеев
4
Я использовал в keyupтечение последнего получаса , пытаясь решить мою проблему, которую вы сделали. Итак, люди, не используйте, keyupчтобы поймать отправленные формы
Нико
52

Использование обработки событий Google кажется правильным решением, но у меня это не работает. Это решение jQuery работает для меня:

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

.pac-container- это div, содержащий совпадения с автозаполнением. Идея состоит в том, что, когда совпадения видны, клавиша Enter просто выбирает активное совпадение. Но когда совпадения скрыты (т. Е. Место выбрано), он отправит форму.

один
источник
прекрасно работает, так что спасибо. просто и эффективно.
luke_mclachlan 05
Наверное, самое элегантное решение. Спасибо!
Николай Трайков
но разве это не позволит вводить форму в пустое поле? перед выбором адреса?
amosmos
1
Это не работает в Chrome. Похоже, что события клавиш Chrome не обнаруживают Enter, если ввод находится внутри формы.
Бруно
1
Единственным недостатком этого решения является то, что если Google решит изменить HTML-код, который они вводят на вашу страницу, и переименовать .pac-containerво что-то другое, это сломается.
Джастин Таннер
21

Я объединил первые два ответа от @sren и @mmalone, чтобы получить следующее:

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

отлично работает на странице. предотвращает отправку формы, когда виден контейнер предложений (.pac-container). Итак, теперь опция из раскрывающегося списка автозаполнения выбирается, когда пользователи нажимают клавишу ввода, и им нужно нажать ее снова, чтобы отправить форму.

Моя основная причина использования этого обходного пути заключается в том, что я обнаружил, что если форма отправляется сразу после выбора опции с помощью клавиши ввода, значения широты и долготы не передаются достаточно быстро в их скрытые элементы формы.

Все заслуги оригинальных ответов.

luke_mclachlan
источник
7

Это сработало для меня:

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

  }

});

Может быть легко преобразован из ES6 в любой код, совместимый с браузером.

Алексей Федосеев
источник
Мне нравится ваш ответ, но мне пришлось немного подправить его, чтобы заставить его работать. Выложил свое решение.
Schulwitz
4

Проблема с ответом @ sren заключалась в том, что он всегда блокирует событие отправки. Мне понравился ответ @ mmalone, но он вел себя случайным образом, так как иногда, когда я нажимал, ENTERчтобы выбрать местоположение, обработчик запускался после того, как контейнер был скрыт. Итак, вот что я в итоге сделал

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>

Флаг гарантирует, что, если местоположение изменяется и пользователь нажимает клавишу ввода, событие блокируется. В конце концов, флаг устанавливается событием falseкарты Google place_changed, которое затем позволяет отправить форму при нажатии клавиши ввода.

Мудасир Али
источник
Этот код действительно сработал для меня, спасибо за ваши усилия!
Аймал Хан
Этот код избегает отправки, если пользователь пишет, нажимает ввод, а затем стрелку вниз (или любую клавишу, которая не запускает автозаполнение). После этого возврат блокируется.
Natxet
1

Вот простой код, который у меня хорошо сработал (без jquery).

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

Этот фрагмент кода, следуя приведенному выше коду, используется для реализации автозаполнения карт Google (с функцией клавиши Enter или без нее, о которой идет речь в этом вопросе):

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 (названный выше в первой части кода) определил:

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

Этот код заставляет поле автозаполнения карт Google выбирать любой элемент, который пользователь выбирает с помощью клавиши со стрелкой вниз. Когда пользователь выбирает параметр нажатием клавиши Enter, ничего не происходит. Пользователь должен снова нажать Enter, чтобы вызвать onSubmit () или другую команду.

coder101
источник
0

Я подправил код Алекса, потому что он сломался в браузере. Это идеально подходит для меня:

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]);
    }
}
Schulwitz
источник
0

Я пробовал приведенные выше короткие ответы, но они не сработали для меня, а длинные ответы я не хотел их пробовать, поэтому я создал следующий код, который мне очень понравился. См. Демонстрацию

Предположим, это ваша форма:

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

Тогда следующий код javascript решит проблему:

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

А вот как выглядит полный код на HTML-странице (обратите внимание, что вам нужно заменить YOUR_API_KEYключ API Google):

<!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>
Амр
источник
0
$("#myinput").on("keydown", function(e) {
if (e.which == 13) {

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

}

Используйте, $('.pac-item:first').trigger('click');если хотите выбрать первый результат

Мул Сингх
источник
0

Сделать это можно в ванили:

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();
     }
 })
Digivia
источник