Autocompletar de Google: ingrese para seleccionar

80

Tengo configurado Google Autocomplete para un campo de texto de un formulario HTML y funciona perfectamente.

Sin embargo, cuando aparece la lista de sugerencias, y usa las flechas para desplazarse y seleccionar usando enter, envía el formulario, aunque todavía hay casillas para completar. Si hace clic para seleccionar una sugerencia, funciona bien, pero presionar enter envía .

¿Cómo puedo controlar esto? ¿Cómo puedo dejar de ingresar y dejar de enviar el formulario y, en cambio, ser la selección de una sugerencia de autocompletar?

¡Gracias! {S}

kinkersnick
fuente

Respuestas:

110

Puede usar preventDefaultpara detener el envío del formulario cuando se presiona Enter, usé algo como esto:

  var input = document.getElementById('inputId');
  google.maps.event.addDomListener(input, 'keydown', function(event) { 
    if (event.keyCode === 13) { 
        event.preventDefault(); 
    }
  }); 
sren
fuente
2
Esto cancelará siempre el envío del campo. Solo lo necesito para cancelar el envío si el usuario ha presionado intro para seleccionar una opción de autocompletar.
A. Matías Quezada
1
Funciona como una joya. Presionar y seleccionar una opción de autocompletar de la lista con Enter ya no envía el formulario.
Eric L.
Esto es más un patrón que una solución. Igual que el uso del controlador onClick para enviar el formulario en lugar del controlador onSubmit. Ingrese debe enviar el formulario.
Alex Fedoseev
4
Estuve usando keyupdurante la última media hora tratando de resolver mi problema, lo cual hiciste. Entonces, gente, no usen keyuppara recibir presentaciones de formularios
Nico
52

Usar el manejo de eventos de Google parece la solución adecuada, pero no me funciona. Esta solución jQuery está funcionando para mí:

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

.pac-containeres el div que contiene las coincidencias de Autocompletar. La idea es que cuando las coincidencias estén visibles, la tecla Enter simplemente seleccionará la coincidencia activa. Pero cuando las coincidencias están ocultas (es decir, se ha elegido un lugar) enviará el formulario.

mmalone
fuente
funciona muy bien así que gracias. simple y eficaz.
luke_mclachlan
Probablemente la solución más elegante. ¡Gracias!
Nikolay Traykov
pero ¿no permitiría eso una entrada que envíe el formulario en un campo vacío? antes de elegir una dirección?
amosmos
1
Esto no funciona en Chrome. Parece que los eventos de las teclas de Chrome no detectan la entrada si la entrada está dentro de un formulario.
Bruno
1
El único inconveniente de esta solución es que si Google decide cambiar el HTML que inyectan en su página y cambiar el nombre .pac-containera otra cosa, esto se romperá.
Justin Tanner
21

He fusionado las dos primeras respuestas de @sren y @mmalone para producir esto:

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

funciona perfectamente en la página. evita que el formulario se envíe cuando el contenedor de sugerencias (.pac-container) está visible. Entonces, ahora, se selecciona una opción del menú desplegable de autocompletar cuando los usuarios presionan la tecla Intro, y tienen que presionarla nuevamente para enviar el formulario.

Mi razón principal para usar esta solución es porque descubrí que si el formulario se envía tan pronto como se selecciona una opción, a través de la tecla Intro, los valores de latitud y longitud no se pasan lo suficientemente rápido a sus elementos de formulario ocultos.

Todo el crédito a las respuestas originales.

luke_mclachlan
fuente
7

Este funcionó para mí:

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

  }

});

Se puede convertir fácilmente de ES6 a cualquier código compatible con el navegador.

Alex Fedoseev
fuente
Me gusta tu respuesta, pero tuve que modificarla un poco para que funcionara. Publicado mi solución.
schulwitz
4

El problema que tuve con la respuesta de @ sren fue que siempre bloquea el evento de envío. Me gustó la respuesta de @ mmalone, pero se comportó de forma aleatoria, ya que a veces cuando presiono ENTERpara seleccionar la ubicación, el controlador se ejecuta después de que el contenedor está oculto. Entonces, esto es lo que terminé haciendo

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>

La bandera asegura que si se cambia la ubicación y el usuario presiona Enter, el evento se bloquea. Finalmente, el evento de falseGoogle Map establece la bandera place_changed, que luego permite que el formulario se envíe al presionar la tecla Intro.

Mudassir Ali
fuente
Este código realmente funcionó para mí, ¡gracias por el esfuerzo!
Aimal Khan
Este código evita enviar si el usuario escribe, presiona enter, luego flecha hacia abajo (o cualquier tecla que no active el autocompletado). Después de esto, el retorno se bloquea.
Natxet
1

Aquí hay un código simple que funcionó bien para mí (no usa jquery).

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

Este fragmento de código, para seguir el código anterior, se utiliza para implementar el autocompletado de mapas de Google (con o sin la funcionalidad de la tecla Enter que se busca en esta pregunta):

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 (llamado arriba en el primer fragmento de código) definido:

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

Este código hace que el campo de autocompletar de Google Maps seleccione cualquier elemento que el usuario seleccione con la tecla de flecha hacia abajo. Una vez que el usuario selecciona una opción presionando la tecla Enter, no sucede nada. El usuario tiene que presionar Enter nuevamente para activar onSubmit () u otro comando

codificador101
fuente
0

Modifiqué el código de Alex porque se rompió en el navegador. Esto funciona perfecto para mí:

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

Probé las respuestas cortas anteriores pero no funcionaron para mí, y las respuestas largas no las quería probar, así que creé el siguiente código que funcionó bastante bien para mí. Ver demostración

Suponga que este es su formulario:

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

Entonces el siguiente código javascript resolverá el problema:

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

Y así es como se ve el código completo en la página HTML (tenga en cuenta que debe reemplazarlo YOUR_API_KEYcon su clave api de 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>
Amr
fuente
0
$("#myinput").on("keydown", function(e) {
if (e.which == 13) {

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

}

Úselo $('.pac-item:first').trigger('click');si desea seleccionar el primer resultado

Mool Singh
fuente
0

Puedes hacerlo en vainilla:

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
fuente