API de datos de Place Autocomplete

La API de datos de Place Autocomplete te permite obtener predicciones de lugares de manera programática para crear experiencias personalizadas de Autocomplete con un mayor control que el que se puede lograr con el widget de Autocomplete. En esta guía, aprenderás a utilizar la API de Place Autocomplete Data para realizar solicitudes de Autocomplete basadas en las consultas de los usuarios.

En el siguiente ejemplo, se muestra una integración de escritura anticipada simple. Ingresa tu búsqueda y, luego, haz clic para seleccionar el resultado que desees.

Solicitudes a Autocomplete

Una solicitud de Autocomplete toma una cadena de entrada de consulta y devuelve una lista de predicciones de lugares. Para realizar una solicitud de autocompletado, llama a fetchAutocompleteSuggestions() y pasa una solicitud con las propiedades necesarias. La propiedad input contiene la cadena que se debe buscar. En una aplicación típica, este valor se actualiza a medida que el usuario escribe una consulta. La solicitud debe incluir un sessionToken, que se usa para fines de facturación.

En el siguiente fragmento, se muestra cómo crear un cuerpo de solicitud, agregar un token de sesión y, luego, llamar a fetchAutocompleteSuggestions() para obtener una lista de PlacePrediction.

// Add an initial request body.
let request = {
  input: "Tadi",
  locationRestriction: {
    west: -122.44,
    north: 37.8,
    east: -122.39,
    south: 37.78,
  },
  origin: { lat: 37.7893, lng: -122.4039 },
  includedPrimaryTypes: ["restaurant"],
  language: "en-US",
  region: "us",
};
// Create a session token.
const token = new AutocompleteSessionToken();

// Add the token to the request.
// @ts-ignore
request.sessionToken = token;

Cómo restringir las predicciones de Autocomplete

De forma predeterminada, Place Autocomplete presenta todos los tipos de lugares, personalizados según la ubicación del usuario, y obtiene información de todos los campos de datos disponibles para el lugar que este selecciona. Configura las opciones de Place Autocomplete para presentar predicciones más relevantes mediante la restricción o personalización de los resultados.

La restricción de resultados hace que el widget de Autocomplete ignore cualquier resultado que esté fuera del área de restricción. Una práctica común es restringir los resultados a los límites del mapa. La personalización de resultados hace que el widget de Autocomplete muestre resultados dentro del área especificada, pero algunas coincidencias pueden estar fuera de esa área.

Usa la propiedad origin para especificar el punto de origen desde el que se calculará la distancia geodésica al destino. Si se omite este valor, no se muestra la distancia.

Usa la propiedad includedPrimaryTypes para especificar hasta cinco tipos de lugares. Si no se especifican tipos, se mostrarán lugares de todos los tipos.

Consulta la referencia de la API

Cómo obtener detalles de un lugar

Para mostrar un objeto Place de un resultado de la predicción de lugar, primero llama a toPlace() y, luego, llama a fetchFields() en el objeto Place resultante (el ID de sesión de la predicción del lugar se incluye automáticamente). La llamada a fetchFields() finaliza la sesión de autocompletado.

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

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

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

placeInfo.textContent =
  "First predicted place: " +
  place.displayName +
  ": " +
  place.formattedAddress;

Tokens de sesión

Los tokens de sesión agrupan las fases de consulta y selección de la búsqueda con autocompletado de un usuario en una sesión discreta para realizar la facturación correspondiente. La sesión comienza cuando el usuario comienza a escribir. La sesión concluye cuando el usuario selecciona un lugar y se realiza una llamada a Place Details.

Para crear un token de sesión nuevo y agregarlo a una solicitud, crea una instancia de AutocompleteSessionToken y, luego, configura la propiedad sessionToken de la solicitud para usar los tokens como se muestra en el siguiente fragmento:

// Create a session token.
const token = new AutocompleteSessionToken();

// Add the token to the request.
// @ts-ignore
request.sessionToken = token;

Una sesión concluye cuando se llama a fetchFields(). Después de crear la instancia Place, no necesitas pasar el token de sesión a fetchFields(), ya que se controla automáticamente.

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

Crea un token de sesión para la siguiente sesión creando una nueva instancia de AutocompleteSessionToken.

Recomendaciones de tokens de sesión:

  • Usar tokens de sesión para todas las llamadas de Place Autocomplete
  • Genera un token nuevo para cada sesión.
  • Pasa un token de sesión único para cada sesión nueva. Usar el mismo token en más de una sesión hará que cada solicitud se facture de forma individual.

De manera opcional, puedes omitir el token de sesión de autocompletado de una solicitud. Si se omite el token de sesión, cada solicitud se factura por separado, lo que activa el SKU Autocomplete, por solicitud. Si vuelves a usar un token de sesión, la sesión se considera no válida y las solicitudes se cobran como si no se hubiera proporcionado un token de sesión.

Ejemplo

A medida que el usuario escribe una consulta, se llama a una solicitud de autocompletado cada pocas veces con una tecla (no por carácter) y se muestra una lista de resultados posibles. Cuando el usuario hace una selección en la lista de resultados, la selección cuenta como una solicitud, y todas las solicitudes realizadas durante la búsqueda se agrupan y cuentan como una sola solicitud. Si el usuario selecciona un lugar, la búsqueda estará disponible sin cargo y solo se cobrará la solicitud de datos de lugar. Si el usuario no hace una selección unos minutos antes del comienzo de la sesión, solo se cobrará la búsqueda.

Desde la perspectiva de una aplicación, el flujo de eventos es así:

  1. Un usuario comienza a escribir una consulta para buscar "París, Francia".
  2. Cuando se detecta la entrada del usuario, la app crea un nuevo token de sesión, “Token A”.
  3. A medida que el usuario escribe, la API realiza una solicitud de autocompletado cada pocos caracteres y muestra una nueva lista de resultados potenciales para cada uno:
    "P"
    "Par"
    "París",
    "París, fra"
  4. Cuando el usuario realiza una selección, ocurre lo siguiente:
    • Todas las solicitudes resultantes de la consulta se agrupan y se agregan a la sesión representada por el “Token A”, como una sola solicitud.
    • La selección del usuario se cuenta como una solicitud de Place Details y se agrega a la sesión representada por el "Token A".
  5. La sesión finaliza y la aplicación descarta el "Token A".
Más información sobre cómo se facturan las sesiones

Ejemplo de código completo

Esta sección contiene ejemplos completos que muestran cómo utilizar la API de datos de Place Autocomplete .

Predicciones de Place Autocomplete

En el siguiente ejemplo, se muestra cómo llamar a fetchAutocompleteSuggestions() para la entrada "Tadi" y, luego, llamar a toPlace() en el primer resultado de la predicción y, luego, llamar a fetchFields() para obtener detalles del lugar.

TypeScript

/**
 * Demonstrates making a single request for Place predictions, then requests Place Details for the first result.
 */
async function init() {
    // @ts-ignore
    const { Place, AutocompleteSessionToken, AutocompleteSuggestion } = await google.maps.importLibrary("places") as google.maps.PlacesLibrary;

    // Add an initial request body.
    let request = {
        input: "Tadi",
        locationRestriction: { west: -122.44, north: 37.8, east: -122.39, south: 37.78 },
        origin: { lat: 37.7893, lng: -122.4039 },
        includedPrimaryTypes: ["restaurant"],
        language: "en-US",
        region: "us",
    };

    // Create a session token.
    const token = new AutocompleteSessionToken();
    // Add the token to the request.
    // @ts-ignore
    request.sessionToken = token;
    // Fetch autocomplete suggestions.
    const { suggestions } = await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);

    const title = document.getElementById('title') as HTMLElement;
    title.appendChild(document.createTextNode('Query predictions for "' + request.input + '":'));

    for (let suggestion of suggestions) {
        const placePrediction = suggestion.placePrediction;

        // Create a new list element.
        const listItem = document.createElement('li');
        const resultsElement = document.getElementById("results") as HTMLElement;
        listItem.appendChild(document.createTextNode(placePrediction.text.toString()));
        resultsElement.appendChild(listItem);
    }

    let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place.
    await place.fetchFields({
        fields: ['displayName', 'formattedAddress'],
    });

    const placeInfo = document.getElementById("prediction") as HTMLElement;
    placeInfo.textContent = 'First predicted place: ' + place.displayName + ': ' + place.formattedAddress;

}

init();

JavaScript

/**
 * Demonstrates making a single request for Place predictions, then requests Place Details for the first result.
 */
async function init() {
  // @ts-ignore
  const { Place, AutocompleteSessionToken, AutocompleteSuggestion } =
    await google.maps.importLibrary("places");
  // Add an initial request body.
  let request = {
    input: "Tadi",
    locationRestriction: {
      west: -122.44,
      north: 37.8,
      east: -122.39,
      south: 37.78,
    },
    origin: { lat: 37.7893, lng: -122.4039 },
    includedPrimaryTypes: ["restaurant"],
    language: "en-US",
    region: "us",
  };
  // Create a session token.
  const token = new AutocompleteSessionToken();

  // Add the token to the request.
  // @ts-ignore
  request.sessionToken = token;

  // Fetch autocomplete suggestions.
  const { suggestions } =
    await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);
  const title = document.getElementById("title");

  title.appendChild(
    document.createTextNode('Query predictions for "' + request.input + '":'),
  );

  for (let suggestion of suggestions) {
    const placePrediction = suggestion.placePrediction;
    // Create a new list element.
    const listItem = document.createElement("li");
    const resultsElement = document.getElementById("results");

    listItem.appendChild(
      document.createTextNode(placePrediction.text.toString()),
    );
    resultsElement.appendChild(listItem);
  }

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

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

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

  placeInfo.textContent =
    "First predicted place: " +
    place.displayName +
    ": " +
    place.formattedAddress;
}

init();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

HTML

<html>
  <head>
    <title>Place Autocomplete Data API Predictions</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="title"></div>
    <ul id="results"></ul>
    <p><span id="prediction"></span></p>
    <img
      class="powered-by-google"
      src="https://storage.googleapis.com/geo-devrel-public-buckets/powered_by_google_on_white.png"
      alt="Powered by Google"
    />

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "weekly"});</script>
  </body>
</html>

Prueba la muestra

Usa la función de autocompletar con sesiones para usar la función de autocompletado

En este ejemplo, se muestra cómo llamar a fetchAutocompleteSuggestions() en función de las consultas de los usuarios, se muestra una lista de lugares de predicción en respuesta y, por último, se recuperan los detalles del lugar seleccionado. En este ejemplo, también se muestra el uso de tokens de sesión para agrupar una consulta de usuario con la solicitud final a Place Details.

TypeScript

let title;
let results;
let input;
let token;

// Add an initial request body.
let request = {
    input: "",
    locationRestriction: { west: -122.44, north: 37.8, east: -122.39, south: 37.78 },
    origin: { lat: 37.7893, lng: -122.4039 },
    includedPrimaryTypes: ["restaurant"],
    language: "en-US",
    region: "us",
};

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

    title = document.getElementById('title');
    results = document.getElementById('results');
    input = document.querySelector("input");
    input.addEventListener("input", makeAcRequest);
    request = refreshToken(request) as any;
}

async function makeAcRequest(input) {
    // Reset elements and exit if an empty string is received.
    if (input.target.value == '') {
        title.innerText = '';
        results.replaceChildren();
        return;
    }

    // Add the latest char sequence to the request.
    request.input = input.target.value;

    // Fetch autocomplete suggestions and show them in a list.
    // @ts-ignore
    const { suggestions } = await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request);

    title.innerText = 'Query predictions for "' + request.input + '"';

    // Clear the list first.
    results.replaceChildren();

    for (const suggestion of suggestions) {
        const placePrediction = suggestion.placePrediction;

        // Create a link for the place, add an event handler to fetch the place.
        const a = document.createElement('a');
        a.addEventListener('click', () => {
            onPlaceSelected(placePrediction.toPlace());
        });
        a.innerText = placePrediction.text.toString();

        // Create a new list element.
        const li = document.createElement('li');
        li.appendChild(a);
        results.appendChild(li);
    }
}

// Event handler for clicking on a suggested place.
async function onPlaceSelected(place) {
    await place.fetchFields({
        fields: ['displayName', 'formattedAddress'],
    });
    let placeText = document.createTextNode(place.displayName + ': ' + place.formattedAddress);
    results.replaceChildren(placeText);
    title.innerText = 'Selected Place:';
    input.value = '';
    refreshToken(request);
}

// Helper function to refresh the session token.
async function refreshToken(request) {
    // Create a new session token and add it to the request.
    token = new google.maps.places.AutocompleteSessionToken();
    request.sessionToken = token;
    return request;
}

declare global {
    interface Window {
      init: () => void;
    }
  }
  window.init = init;

JavaScript

let title;
let results;
let input;
let token;
// Add an initial request body.
let request = {
  input: "",
  locationRestriction: {
    west: -122.44,
    north: 37.8,
    east: -122.39,
    south: 37.78,
  },
  origin: { lat: 37.7893, lng: -122.4039 },
  includedPrimaryTypes: ["restaurant"],
  language: "en-US",
  region: "us",
};

async function init() {
  token = new google.maps.places.AutocompleteSessionToken();
  title = document.getElementById("title");
  results = document.getElementById("results");
  input = document.querySelector("input");
  input.addEventListener("input", makeAcRequest);
  request = refreshToken(request);
}

async function makeAcRequest(input) {
  // Reset elements and exit if an empty string is received.
  if (input.target.value == "") {
    title.innerText = "";
    results.replaceChildren();
    return;
  }

  // Add the latest char sequence to the request.
  request.input = input.target.value;

  // Fetch autocomplete suggestions and show them in a list.
  // @ts-ignore
  const { suggestions } =
    await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(
      request,
    );

  title.innerText = 'Query predictions for "' + request.input + '"';
  // Clear the list first.
  results.replaceChildren();

  for (const suggestion of suggestions) {
    const placePrediction = suggestion.placePrediction;
    // Create a link for the place, add an event handler to fetch the place.
    const a = document.createElement("a");

    a.addEventListener("click", () => {
      onPlaceSelected(placePrediction.toPlace());
    });
    a.innerText = placePrediction.text.toString();

    // Create a new list element.
    const li = document.createElement("li");

    li.appendChild(a);
    results.appendChild(li);
  }
}

// Event handler for clicking on a suggested place.
async function onPlaceSelected(place) {
  await place.fetchFields({
    fields: ["displayName", "formattedAddress"],
  });

  let placeText = document.createTextNode(
    place.displayName + ": " + place.formattedAddress,
  );

  results.replaceChildren(placeText);
  title.innerText = "Selected Place:";
  input.value = "";
  refreshToken(request);
}

// Helper function to refresh the session token.
async function refreshToken(request) {
  // Create a new session token and add it to the request.
  token = new google.maps.places.AutocompleteSessionToken();
  request.sessionToken = token;
  return request;
}

window.init = init;

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

a {
  cursor: pointer;
  text-decoration: underline;
  color: blue;
}

input {
  width: 300px;
}

HTML

<html>
  <head>
    <title>Place Autocomplete Data API Session</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <input id="input" type="text" placeholder="Search for a place..." />
    <div id="title"></div>
    <ul id="results"></ul>
    <img
      class="powered-by-google"
      src="https://storage.googleapis.com/geo-devrel-public-buckets/powered_by_google_on_white.png"
      alt="Powered by Google"
    />

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=init&libraries=places&v=weekly"
      defer
    ></script>
  </body>
</html>

Prueba la muestra