Cómo migrar al nuevo Place Autocomplete

Place Autocomplete es una función de la biblioteca de Places de la API de Maps JavaScript. Puedes usar esta función para incluir en tus aplicaciones el comportamiento de escritura anticipada del campo de búsqueda de Google Maps.

En esta página, se explican las diferencias entre las funciones heredadas y las nuevas de Place Autocomplete. En ambas versiones, existen dos formas generales de integrar Autocomplete:

Interfaz programática de Autocomplete

En la siguiente tabla, se enumeran algunas de las principales diferencias en el uso del autocompletado de lugares programático entre el servicio Place Autocomplete (heredado) y la API de Autocomplete Data (nueva):

PlacesService (heredada) Place (nuevo)
Referencia del servicio Place Autocomplete Referencia de Autocomplete Data (new)
AutocompletionRequest AutocompleteRequest
AutocompleteService.getPlacePredictions AutocompleteSuggestion.fetchAutocompleteSuggestions
AutocompletePrediction PlacePrediction
Los métodos requieren el uso de una devolución de llamada para controlar el objeto de resultados y la respuesta de PlacesServiceStatus. Usa promesas y funciona de forma asíncrona.
Los métodos requieren una verificación de PlacesServiceStatus. No se requiere verificación de estado, se puede usar el manejo de errores estándar.
Los campos de datos de Place se establecen como opciones cuando se crea la instancia de Autocomplete. Los campos de datos de Place se establecen más adelante cuando se llama a fetchFields().
Se admiten las predicciones de consultas (solo SearchBox). Las predicciones de consultas no están disponibles en la clase Autocomplete.
Se limita a un conjunto fijo de tipos de lugares y campos de datos de lugares. Acceso a una selección expandida de tipos de lugares y campos de datos de lugares.

Las APIs de Autocomplete heredada y nueva usan lo siguiente:

Comparación de código (programática)

En esta sección, se compara el código de autocompletado para ilustrar las diferencias entre el servicio de Places y la clase Place para interfaces programáticas.

Cómo recuperar predicciones de autocompletar (heredado)

El servicio de Places heredado te permite recuperar predicciones de autocompletado de forma programática para tener más control sobre la interfaz de usuario que ofrece la clase Autocomplete. En el siguiente ejemplo, se realiza una sola solicitud para “par”, con un AutocompletionRequest que consta del valor de entrada y un conjunto de límites para sesgar la predicción. El ejemplo muestra una lista de instancias de AutocompletePrediction y muestra la descripción de cada una. La función de ejemplo también crea un token de sesión y lo aplica a la solicitud.

function init() {
  const placeInfo = document.getElementById("prediction");
  const service = new google.maps.places.AutocompleteService();
  const placesService = new google.maps.places.PlacesService(placeInfo);
  var sessionToken = new google.maps.places.AutocompleteSessionToken();

  // Define request options.
  let request = {
    input: "par",
    sessionToken: sessionToken,
    bounds: {
      west: -122.44,
      north: 37.8,
      east: -122.39,
      south: 37.78,
    },
  }

  // Display the query string.
  const title = document.getElementById("title");
  title.appendChild(
    document.createTextNode('Place predictions for "' + request.input + '":'),
  );

  // Perform the query and display the results.
  const displaySuggestions = function (predictions, status) {
    // Check the status of the Places Service.
    if (status != google.maps.places.PlacesServiceStatus.OK || !predictions) {
      alert(status);
      return;
    }

    predictions.forEach((prediction) => {
      const li = document.createElement("li");
      li.appendChild(document.createTextNode(prediction.description));
      document.getElementById("results").appendChild(li);
    });

    const placeRequest = {
      placeId: predictions[0].place_id,
      fields: ["name", "formatted_address"],
    };

    placesService.getDetails(placeRequest, (place, status) => {
      if (status == google.maps.places.PlacesServiceStatus.OK && place) {
        placeInfo.textContent = `
          First predicted place: ${place.name} at ${place.formatted_address}`
      }
    });

  };

  // Show the results of the query.
  service.getPlacePredictions(request, displaySuggestions);
}

Cómo recuperar predicciones de Autocomplete (nueva)

La nueva clase Place también te permite recuperar predicciones de autocompletado de forma programática para tener más control sobre la interfaz de usuario que el que ofrece la clase PlaceAutocompleteElement. En el siguiente ejemplo, se realiza una sola solicitud para “par”, con un AutocompleteRequest que consta del valor de entrada y un conjunto de límites para sesgar la predicción. El ejemplo muestra una lista de instancias de placePrediction y muestra la descripción de cada una. La función de ejemplo también crea un token de sesión y lo aplica a la solicitud.

async function init() {
  let sessionToken = new google.maps.places.AutocompleteSessionToken();

  // Define request options.
  let request = {
    input: "par",
    sessionToken: sessionToken,
    locationBias: {
      west: -122.44,
      north: 37.8,
      east: -122.39,
      south: 37.78,
    },
  };

  // Display the query string.
  const title = document.getElementById("title");
  title.appendChild(
    document.createTextNode('Place predictions for "' + request.input + '":'),
  );

  // Perform the query and display the results.
  const { suggestions } =
    await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request);

  const resultsElement = document.getElementById("results");

  for (let suggestion of suggestions) {
    const placePrediction = suggestion.placePrediction;
    const listItem = document.createElement("li");

    listItem.appendChild(
      document.createTextNode(placePrediction.text.text),
    );

    resultsElement.appendChild(listItem);
  }

  // Show the first predicted place.
  let place = suggestions[0].placePrediction.toPlace();

  await place.fetchFields({
    fields: ["displayName", "formattedAddress"],
  });

  const placeInfo = document.getElementById("prediction");

  placeInfo.textContent = `
    First predicted place: ${place.displayName} at ${place.formattedAddress}`
}

Widget de autocompletado de lugares

En la siguiente tabla, se enumeran algunas de las diferencias principales en el uso de widgets de autocompletado entre el servicio de Places (heredado) y la clase Place (nueva):

Servicio de Places (heredado) Place (nuevo)
Clase Autocomplete para las predicciones de lugares. Clase PlaceAutocompleteElement para las predicciones de lugares.
Clase SearchBox
para las predicciones de consultas.
Las predicciones de consultas no están disponibles en la clase Autocomplete.
Solo se localiza el texto del marcador de posición de entrada predeterminado. El marcador de posición de entrada de texto, el logotipo de la lista de predicciones y las predicciones sobre lugares admiten la localización regional.
El widget usa setBounds() o autocomplete.bindTo() para restringir (polarizar) la búsqueda a los límites especificados y strictBounds para restringir los resultados a los límites especificados. El widget usa la propiedad locationBias para sesgar los resultados a los límites especificados y la propiedad locationRestriction para restringir la búsqueda a los límites especificados.
Los widgets solo se pueden integrar con un elemento de entrada HTML estándar. El widget se puede integrar con un elemento de entrada HTML estándar o un elemento gmp-place-autocomplete.
Cuando se usa el widget, los usuarios pueden solicitar elementos que pueden no ser válidos (por ejemplo, "bisneyland"). Este caso se debe controlar de forma explícita. El widget solo mostrará resultados para las sugerencias proporcionadas y no puede emitir solicitudes de valores arbitrarios. Por lo tanto, no es necesario controlar las solicitudes potencialmente no válidas.
Muestra una instancia heredada de PlaceResult. Muestra una instancia de Place.
Los campos de datos de Place se configuran como opciones para el objeto Autocomplete. Los campos de datos de Place se establecen cuando el usuario realiza una selección y se llama a fetchFields().
Se limita a un conjunto fijo de tipos de lugares y campos de datos de lugares. Acceso a una selección expandida de tipos de lugares y campos de datos de lugares.

Comparación de código (widgets)

En esta sección, se compara el código de autocompletado para ilustrar las diferencias entre el widget heredado de Place Autocomplete y el nuevo elemento de Place Autocomplete.

Widget de Place Autocomplete (heredado)

El servicio de Places ofrece dos tipos de widgets de autocompletado que puedes agregar con las clases Autocomplete y SearchBox. Cada tipo de widget se puede agregar a un mapa como control de mapa o incorporar directamente en una página web. En el siguiente ejemplo de código, se muestra cómo incorporar un widget Autocomplete como control de mapa.

  • El constructor del widget Autocomplete toma dos argumentos:
    • Un elemento HTML input de tipo text: El servicio de autocompletado controlará este campo de entrada y le adjuntará sus resultados.
    • Un argumento AutocompleteOptions opcional, en el que puedes especificar más opciones para restringir la consulta.
  • Para establecer límites, la instancia de Autocomplete se puede vincular de forma explícita al mapa llamando a autocomplete.bindTo().
  • Especifica los campos de datos de lugares en las opciones de autocompletado.
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.749933, lng: -73.98633 },
    zoom: 13,
    mapTypeControl: false,
  });
  const card = document.getElementById("pac-card");
  const input = document.getElementById("pac-input");
  const options = {
    fields: ["formatted_address", "geometry", "name"],
    strictBounds: false,
  };

  map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);

  const autocomplete = new google.maps.places.Autocomplete(input, options);

  // Bind the map's bounds (viewport) property to the autocomplete object,
  // so that the autocomplete requests use the current map bounds for the
  // bounds option in the request.
  autocomplete.bindTo("bounds", map);

  const infowindow = new google.maps.InfoWindow();
  const infowindowContent = document.getElementById("infowindow-content");

  infowindow.setContent(infowindowContent);

  const marker = new google.maps.Marker({
    map,
    anchorPoint: new google.maps.Point(0, -29),
  });

  autocomplete.addListener("place_changed", () => {
    infowindow.close();
    marker.setVisible(false);

    const place = autocomplete.getPlace();

    if (!place.geometry || !place.geometry.location) {
      // User entered the name of a Place that was not suggested and
      // pressed the Enter key, or the Place Details request failed.
      window.alert("No details available for input: '" + place.name + "'");
      return;
    }

    // If the place has a geometry, then present it on a map.
    if (place.geometry.viewport) {
      map.fitBounds(place.geometry.viewport);
    } else {
      map.setCenter(place.geometry.location);
      map.setZoom(17);
    }

    marker.setPosition(place.geometry.location);
    marker.setVisible(true);
    infowindowContent.children["place-name"].textContent = place.name;
    infowindowContent.children["place-address"].textContent =
      place.formatted_address;
    infowindow.open(map, marker);
  });
}

Widget de Place Autocomplete (nuevo)

La clase Place ofrece PlaceAutocompleteElement, una subclase de HTMLElement que proporciona un componente de IU que se puede agregar a un mapa como control de mapa o incorporar directamente en una página web. En el siguiente ejemplo de código, se muestra cómo incorporar un widget PlaceAutocompleteElement como control de mapa.

El widget de Place Autocomplete incluye las siguientes mejoras:

  • La IU del widget de Autocomplete admite la localización regional (incluidos los idiomas RTL) para el marcador de posición de entrada de texto, el logotipo de la lista de predicciones y las predicciones sobre lugares.
  • Se mejoró la accesibilidad, incluida la compatibilidad con los lectores de pantalla y la interacción con el teclado.
  • El widget de Autocomplete muestra la nueva clase Place para simplificar el manejo del objeto que se devuelve.
  • Incluye una mejor compatibilidad con dispositivos móviles y pantallas pequeñas.
  • Tiene un mejor rendimiento y una apariencia gráfica mejorada.

Estas son algunas de las diferencias clave en la implementación:

  • Las predicciones de consultas no están disponibles en la clase Autocomplete.
  • El PlaceAutocompleteElement se construye con PlaceAutocompleteElementOptions.
  • Los campos de datos de Place se especifican en el momento de la selección (cuando se llama a fetchFields()).
  • Para establecer límites, usa la opción locationBounds o locationRestriction.
  • Asocia el PlaceAutocompleteElement con un elemento de entrada de texto HTML con el atributo id (heredado de HTMLElement).
let map;
let marker;
let infoWindow;

async function initMap() {
  // Request needed libraries.
  const [{ Map }, { AdvancedMarkerElement }] = await Promise.all([
    google.maps.importLibrary("marker"),
    google.maps.importLibrary("places"),
  ]);

  // Initialize the map.
  map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.749933, lng: -73.98633 },
    zoom: 13,
    mapId: "4504f8b37365c3d0",
    mapTypeControl: false,
  });

  const placeAutocomplete =
    new google.maps.places.PlaceAutocompleteElement({
      locationRestriction: map.getBounds(),
    });

  placeAutocomplete.id = "place-autocomplete-input";
  const card = document.getElementById("place-autocomplete-card");

  card.appendChild(placeAutocomplete);
  map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);

  // Create the marker and infowindow.
  marker = new google.maps.marker.AdvancedMarkerElement({
    map,
  });
  infoWindow = new google.maps.InfoWindow({});

  // Add the gmp-placeselect listener, and display the results on the map.
  placeAutocomplete.addEventListener("gmp-placeselect", async ({ place }) => {
    await place.fetchFields({
      fields: ["displayName", "formattedAddress", "location"],
    });
    // If the place has a geometry, then present it on a map.
    if (place.viewport) {
      map.fitBounds(place.viewport);
    } else {
      map.setCenter(place.location);
      map.setZoom(17);
    }

    let content =
      '<div id="infowindow-content">' +
      '<span id="place-displayname" class="title">' +
      place.displayName +
      '</span><br />' +
      '<span id="place-address">' +
      place.formattedAddress +
      '</span>' +
      '</div>';

    updateInfoWindow(content, place.location);
    marker.position = place.location;
  });
}

// Helper function to create an info window.
function updateInfoWindow(content, center) {
  infoWindow.setContent(content);
  infoWindow.setPosition(center);
  infoWindow.open({
    map,
    anchor: marker,
    shouldFocus: false,
  });
}