Creare un'interfaccia di ricerca con il widget Ricerca

Il widget di ricerca fornisce un'interfaccia di ricerca personalizzabile per le applicazioni web. Richiede un codice HTML e JavaScript minimo per l'implementazione e supporta funzionalità comuni come sfaccettature e paginazione. Puoi anche personalizzare l'interfaccia con CSS e JavaScript.

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

Crea un'interfaccia di ricerca

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

  1. Configurare 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 sulla pagina.
  5. Inizializza il widget.

Configurare un'applicazione di ricerca

Ogni interfaccia di ricerca richiede un'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 Crea un'esperienza di ricerca personalizzata.

Generare un ID client per l'applicazione

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

Configurare un progetto

Durante la configurazione del progetto:

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

Per saperne di più, 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 dai relativi 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 tag <script>:

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 onload richiamo. Quando il caricatore è pronto, chiama gapi.load() per caricare il client API, l'accesso con Google e i moduli di 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 del builder 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 gli utenti direttamente

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

Preautorizza l'applicazione per gli utenti della tua organizzazione per semplificare l'accesso. Ciò è utile anche con Cloud Identity Aware Proxy. Vedi Utilizzare Accedi con Google con le app IT.

Personalizzare l'interfaccia

Puoi modificare l'aspetto del widget:

  • Sovrascrittura degli stili con CSS.
  • Decorare gli elementi con un adattatore.
  • Creazione di elementi personalizzati con un adattatore.

Sovrascrivere gli stili con CSS

Il widget include il proprio CSS. Per ignorarlo, utilizza i selettori 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 i tag HTML <template>:

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 delle sfaccettature personalizzate devono rispettare queste regole:

  • Collega cloudsearch_facet_bucket_clickable agli elementi cliccabili.
  • Racchiudi ogni bucket in un elemento cloudsearch_facet_bucket_container.
  • Mantenere l'ordine dei bucket della risposta.

Ad esempio, il seguente snippet esegue il rendering delle sfaccettature 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 una fonte 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 il filtro 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 codice seguente 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 alla ricerca implementando interceptSearchResponse nell'adattatore.

Bloccare 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 impostati, entrambi i valori predefiniti sono 1.0.

Ad esempio, per bloccare il widget sulla 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 per la sicurezza delle 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;