Creare un'interfaccia di ricerca con il widget Ricerca

Il widget di ricerca fornisce un'interfaccia di ricerca personalizzabile per le applicazioni web. Per l'implementazione sono necessari HTML e JavaScript minimi e supporta funzionalità comuni come facet e paginazione. Puoi anche personalizzare l'interfaccia con CSS e JavaScript.

Se hai bisogno di maggiore flessibilità, utilizza la Query API. Consulta Creare un'interfaccia di ricerca con la Query API.

Creare un'interfaccia di ricerca

La creazione dell'interfaccia di ricerca richiede i seguenti passaggi:

  1. Configura un'applicazione di ricerca.
  2. Genera un ID client per l'applicazione.
  3. Aggiungi il markup HTML per la casella di ricerca e i risultati.
  4. Carica il widget nella pagina.
  5. Inizializza il widget.

Configurare un'applicazione di ricerca

Ogni interfaccia di ricerca richiede una applicazione di ricerca definita nella Console di amministrazione. L'applicazione fornisce impostazioni di query, come origini dati, facet e parametri di qualità della ricerca.

Per creare un'applicazione di ricerca, consulta Creare un'esperienza di ricerca personalizzata.

Generare un ID client per l'applicazione

Oltre ai passaggi descritti in Configurare l'accesso alla Cloud Search API, genera un ID client per la tua applicazione web.

Configurare un progetto

Quando configuri il progetto:

  • Seleziona il tipo di client Browser web.
  • Fornisci l'URI di origine della tua app.
  • Prendi nota dell'ID client. Il widget non richiede un client secret.

Per ulteriori informazioni, consulta OAuth 2.0 per applicazioni web lato client.

Aggiungere il markup HTML

Il widget richiede i seguenti elementi HTML:

  • Un elemento input per la casella di ricerca.
  • Un elemento per ancorare la finestra di dialogo dei suggerimenti.
  • Un elemento per i risultati di ricerca.
  • (Facoltativo) Un elemento per i controlli dei facet.

Questo snippet mostra gli elementi identificati dagli attributi id:

serving/widget/public/with_css/index.html
<div id="search_bar">
  <div id="suggestions_anchor">
    <input type="text" id="search_input" placeholder="Search for...">
  </div>
</div>
<div id="facet_results"></div>
<div id="search_results"></div>

Caricare il widget

Includi il caricatore utilizzando un <script> tag:

serving/widget/public/with_css/index.html
<!-- Google API loader -->
<script src="https://apis.google.com/js/api.js?mods=enable_cloud_search_widget&onload=onLoad" async defer></script>

Fornisci un callback onload. Quando il caricatore è pronto, chiama gapi.load() per caricare il client API, Accedi con Google e i moduli Cloud Search.

serving/widget/public/with_css/app.js
/**
* Load the cloud search widget & auth libraries. Runs after
* the initial gapi bootstrap library is ready.
*/
function onLoad() {
  gapi.load('client:auth2:cloudsearch-widget', initializeApp)
}

Inizializzare il widget

Inizializza la libreria client utilizzando gapi.client.init() o gapi.auth2.init() con il tuo ID client e l'ambito https://www.googleapis.com/auth/cloud_search.query. Utilizza le classi di creazione per configurare e associare il widget.

Esempio di inizializzazione:

serving/widget/public/with_css/app.js
/**
 * Initialize the app after loading the Google API client &
 * Cloud Search widget.
 */
function initializeApp() {
  // Load client ID & search app.
  loadConfiguration().then(function() {
    // Set API version to v1.
    gapi.config.update('cloudsearch.config/apiVersion', 'v1');

    // Build the result container and bind to DOM elements.
    var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
      .setSearchApplicationId(searchApplicationName)
      .setSearchResultsContainerElement(document.getElementById('search_results'))
      .setFacetResultsContainerElement(document.getElementById('facet_results'))
      .build();

    // Build the search box and bind to DOM elements.
    var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
      .setSearchApplicationId(searchApplicationName)
      .setInput(document.getElementById('search_input'))
      .setAnchor(document.getElementById('suggestions_anchor'))
      .setResultsContainer(resultsContainer)
      .build();
  }).then(function() {
    // Init API/oauth client w/client ID.
    return gapi.auth2.init({
        'clientId': clientId,
        'scope': 'https://www.googleapis.com/auth/cloud_search.query'
    });
  });
}

Variabili di configurazione:

serving/widget/public/with_css/app.js
/**
* Client ID from OAuth credentials.
*/
var clientId = "...apps.googleusercontent.com";

/**
* Full resource name of the search application, such as
* "searchapplications/<your-id>".
*/
var searchApplicationName = "searchapplications/...";

Personalizzare l'esperienza di accesso

Il widget chiede agli utenti di accedere quando iniziano a digitare. Puoi utilizzare Accedi con Google per i siti web per un'esperienza personalizzata.

Autorizzare direttamente gli utenti

Utilizza Accedi con Google per monitorare e gestire gli stati di accesso. Questo esempio utilizza GoogleAuth.signIn() al clic di un pulsante:

serving/widget/public/with_signin/app.js
// Handle sign-in/sign-out.
let auth = gapi.auth2.getAuthInstance();

// Watch for sign in status changes to update the UI appropriately.
let onSignInChanged = (isSignedIn) => {
  // Update UI to switch between signed in/out states
  // ...
}
auth.isSignedIn.listen(onSignInChanged);
onSignInChanged(auth.isSignedIn.get()); // Trigger with current status.

// Connect sign-in/sign-out buttons.
document.getElementById("sign-in").onclick = function(e) {
  auth.signIn();
};
document.getElementById("sign-out").onclick = function(e) {
  auth.signOut();
};

Consentire l'accesso automatico agli utenti

Pre-autorizza l'applicazione per gli utenti della tua organizzazione per semplificare l'accesso. Questa operazione è utile anche con Cloud Identity Aware Proxy. Consulta Utilizzare Accedi con Google con le app IT Apps.

Personalizzare l'interfaccia

Puoi modificare l'aspetto del widget:

  • Eseguendo l'override degli stili con CSS.
  • Decorando gli elementi con un adattatore.
  • Creando elementi personalizzati con un adattatore.

Eseguire l'override degli stili con CSS

Il widget include il proprio CSS. Per eseguirne l'override, utilizza i selettori di antenati per aumentare la specificità:

#suggestions_anchor .cloudsearch_suggestion_container {
  font-size: 14px;
}

Consulta il riferimento Classi CSS supportate.

Decorare gli elementi con un adattatore

Crea e registra un adattatore per modificare gli elementi prima del rendering. Questo esempio aggiunge una classe CSS personalizzata:

serving/widget/public/with_decorated_element/app.js
/**
 * Search box adapter that decorates suggestion elements by
 * adding a custom CSS class.
 */
function SearchBoxAdapter() {}
SearchBoxAdapter.prototype.decorateSuggestionElement = function(element) {
  element.classList.add('my-suggestion');
}

/**
 * Results container adapter that decorates suggestion elements by
 * adding a custom CSS class.
 */
function ResultsContainerAdapter() {}
ResultsContainerAdapter.prototype.decorateSearchResultElement = function(element) {
  element.classList.add('my-result');
}

Registra l'adattatore durante l'inizializzazione:

serving/widget/public/with_decorated_element/app.js
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(new ResultsContainerAdapter())
  // ...
  .build();

// Build the search box and bind to DOM elements.
var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
  .setAdapter(new SearchBoxAdapter())
  // ...
  .build();

Creare elementi personalizzati con un adattatore

Implementa createSuggestionElement, createFacetResultElement o createSearchResultElement per creare componenti UI personalizzati. Questo esempio utilizza HTML <template> tag:

serving/widget/public/with_custom_element/app.js
/**
 * Search box adapter that overrides creation of suggestion elements.
 */
function SearchBoxAdapter() {}
SearchBoxAdapter.prototype.createSuggestionElement = function(suggestion) {
  let template = document.querySelector('#suggestion_template');
  let fragment = document.importNode(template.content, true);
  fragment.querySelector('.suggested_query').textContent = suggestion.suggestedQuery;
  return fragment.firstElementChild;
}

/**
 * Results container adapter that overrides creation of result elements.
 */
function ResultsContainerAdapter() {}
ResultsContainerAdapter.prototype.createSearchResultElement = function(result) {
  let template = document.querySelector('#result_template');
  let fragment = document.importNode(template.content, true);
  fragment.querySelector('.title').textContent = result.title;
  fragment.querySelector('.title').href = result.url;
  let snippetText = result.snippet != null ?
    result.snippet.snippet : '';
  fragment.querySelector('.query_snippet').innerHTML = snippetText;
  return fragment.firstElementChild;
}

Registra l'adattatore:

serving/widget/public/with_custom_element/app.js
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(new ResultsContainerAdapter())
  // ...
  .build();

// Build the search box and bind to DOM elements.
var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
  .setAdapter(new SearchBoxAdapter())
  // ...
  .build();

Gli elementi dei facet personalizzati devono rispettare le seguenti regole:

  • Collega cloudsearch_facet_bucket_clickable agli elementi su cui è possibile fare clic.
  • Inserisci ogni bucket in un cloudsearch_facet_bucket_container.
  • Mantieni l'ordine dei bucket dalla risposta.

Ad esempio, lo snippet seguente esegue il rendering dei facet utilizzando i link anziché le caselle di controllo.

serving/widget/public/with_custom_facet/app.js
/**
 * Results container adapter that intercepts requests to dynamically
 * change which sources are enabled based on user selection.
 */
function ResultsContainerAdapter() {
  this.selectedSource = null;
}

ResultsContainerAdapter.prototype.createFacetResultElement = function(result) {
  // container for the facet
  var container = document.createElement('div');

  // Add a label describing the facet (operator/property)
  var label = document.createElement('div')
  label.classList.add('facet_label');
  label.textContent = result.operatorName;
  container.appendChild(label);

  // Add each bucket
  for(var i in result.buckets) {
    var bucket = document.createElement('div');
    bucket.classList.add('cloudsearch_facet_bucket_container');

    // Extract & render value from structured value
    // Note: implementation of renderValue() not shown
    var bucketValue = this.renderValue(result.buckets[i].value)
    var link = document.createElement('a');
    link.classList.add('cloudsearch_facet_bucket_clickable');
    link.textContent = bucketValue;
    bucket.appendChild(link);
    container.appendChild(bucket);
  }
  return container;
}

// Renders a value for user display
ResultsContainerAdapter.prototype.renderValue = function(value) {
  // ...
}

Personalizzare il comportamento di ricerca

Esegui l'override delle impostazioni dell'applicazione di ricerca intercettando le richieste con un adattatore. Implementa interceptSearchRequest per modificare le richieste prima dell'esecuzione. Questo esempio limita le query a un'origine selezionata:

serving/widget/public/with_request_interceptor/app.js
/**
 * Results container adapter that intercepts requests to dynamically
 * change which sources are enabled based on user selection.
 */
function ResultsContainerAdapter() {
  this.selectedSource = null;
}
ResultsContainerAdapter.prototype.interceptSearchRequest = function(request) {
  if (!this.selectedSource || this.selectedSource == 'ALL') {
    // Everything selected, fall back to sources defined in the search
    // application.
    request.dataSourceRestrictions = null;
  } else {
    // Restrict to a single selected source.
    request.dataSourceRestrictions = [
      {
        source: {
          predefinedSource: this.selectedSource
        }
      }
    ];
  }
  return request;
}

Registra l'adattatore:

serving/widget/public/with_request_interceptor/app.js
var resultsContainerAdapter = new ResultsContainerAdapter();
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(resultsContainerAdapter)
  // ...
  .build();

Il seguente codice HTML viene utilizzato per visualizzare una casella di selezione per filtrare in base alle origini:

serving/widget/public/with_request_interceptor/index.html
<div>
  <span>Source</span>
  <select id="sources">
    <option value="ALL">All</option>
    <option value="GOOGLE_GMAIL">Gmail</option>
    <option value="GOOGLE_DRIVE">Drive</option>
    <option value="GOOGLE_SITES">Sites</option>
    <option value="GOOGLE_GROUPS">Groups</option>
    <option value="GOOGLE_CALENDAR">Calendar</option>
    <option value="GOOGLE_KEEP">Keep</option>
  </select>
</div>

Il seguente codice rileva la modifica, imposta la selezione e riesegue la query, se necessario.

serving/widget/public/with_request_interceptor/app.js
// Handle source selection
document.getElementById('sources').onchange = (e) => {
  resultsContainerAdapter.selectedSource = e.target.value;
  let request = resultsContainer.getCurrentRequest();
  if (request.query) {
    // Re-execute if there's a valid query. The source selection
    // will be applied in the interceptor.
    resultsContainer.resetState();
    resultsContainer.executeRequest(request);
  }
}

Puoi anche intercettare la risposta di ricerca implementando interceptSearchResponse nell'adattatore.

Fissare le versioni

  • Versione API: imposta cloudsearch.config/apiVersion prima dell'inizializzazione.
  • Versione del widget: utilizza gapi.config.update('cloudsearch.config/clientVersion', 1.1).

Se non impostate, entrambe le versioni predefinite sono 1.0.

Ad esempio, per fissare il widget alla versione 1.1:

serving/widget/public/basic/app.js
gapi.config.update('cloudsearch.config/apiVersion', 'v1');

Proteggere l'interfaccia di ricerca

Segui le best practice di sicurezza per le applicazioni web, in particolare per prevenire il clickjacking.

Attivare il debug

Utilizza interceptSearchRequest per attivare il debug:

if (!request.requestOptions) {
  request.requestOptions = {};
}
request.requestOptions.debugOptions = {enableDebugging: true};
return request;