Suchoberfläche mit dem Such-Widget erstellen

Mit dem Such-Widget steht Ihnen eine anpassbare Suchoberfläche für Webanwendungen zur Verfügung. Für die Implementierung sind nur wenig HTML- und JavaScript-Code erforderlich und gängige Funktionen wie Facetten und Paginierung werden unterstützt. Sie können die Benutzeroberfläche auch mit CSS und JavaScript anpassen.

Wenn Sie mehr Flexibilität benötigen, verwenden Sie die Query API. Weitere Informationen zum Erstellen einer Suchoberfläche mit der Query API

Suchoberfläche erstellen

So erstellen Sie eine Suchoberfläche:

  1. Suchanwendung konfigurieren
  2. Generieren Sie eine Client-ID für die Anwendung.
  3. Fügen Sie dem Suchfeld und den Suchergebnissen HTML-Markup hinzu.
  4. Laden Sie das Widget auf die Seite.
  5. Initialisieren Sie das Widget.

Suchanwendung konfigurieren

Für jede Suchoberfläche muss in der Admin-Konsole eine Suchanwendung definiert werden. Die Anwendung enthält Abfrageeinstellungen wie Datenquellen, Facetten und Parameter für die Suchqualität.

Informationen zum Erstellen einer Suchanwendung finden Sie unter Benutzerdefinierte Suche erstellen.

Client-ID für die Anwendung generieren

Zusätzlich zu den Schritten im Artikel Zugriff auf die Cloud Search API konfigurieren müssen Sie eine Client-ID für Ihre Webanwendung erstellen.

Projekt konfigurieren

Bei der Konfiguration des Projekts sollten Sie Folgendes tun:

  • Wählen Sie als Clienttyp Webbrowser aus.
  • Geben Sie den Origin-URI Ihrer App an.
  • Notieren Sie sich die Client-ID. Für das Widget ist kein Clientschlüssel erforderlich.

Weitere Informationen finden Sie unter OAuth 2.0 für clientseitige Webanwendungen.

HTML-Markup hinzufügen

Für das Widget sind die folgenden HTML-Elemente erforderlich:

  • Ein input-Element für das Suchfeld.
  • Ein Element, um das Dialogfeld für Vorschläge zu verankern
  • Ein Element für Suchergebnisse.
  • Optional: Ein Element für die Steuerelemente für Facets.

In diesem Snippet werden Elemente anhand ihrer id-Attribute identifiziert:

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>

Widget laden

Binden Sie den Loader mit einem <script>-Tag ein:

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>

Einen onload-Callback bereitstellen. Wenn der Loader bereit ist, rufen Sie gapi.load() auf, um den API-Client, Google Log-in und die Cloud Search-Module zu laden.

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

Widget initialisieren

Initialisieren Sie die Clientbibliothek mit gapi.client.init() oder gapi.auth2.init() mit Ihrer Client-ID und dem Bereich https://www.googleapis.com/auth/cloud_search.query. Verwenden Sie die Builder-Klassen, um das Widget zu konfigurieren und zu binden.

Beispiel für die Initialisierung:

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

Konfigurationsvariablen:

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/...";

Anmeldung anpassen

Nutzer werden vom Widget aufgefordert, sich anzumelden, sobald sie mit der Eingabe beginnen. Mithilfe von Über Google anmelden für Websites können Sie Ihren Nutzern eine individuellere Anmeldung anbieten.

Nutzer direkt autorisieren

Verwenden Sie Über Google anmelden, um Anmeldestatus zu überwachen und zu verwalten. In diesem Beispiel wird GoogleAuth.signIn() bei einem Klick auf eine Schaltfläche verwendet:

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

Nutzer automatisch anmelden

Sie können die Anmeldung optimieren, indem Sie die Anwendung für Nutzer in Ihrer Organisation vorab autorisieren. Das ist auch bei Cloud Identity-Aware Proxy nützlich. Weitere Informationen finden Sie unter Google Log-in mit IT-Apps verwenden.

Schnittstelle anpassen

Sie können das Aussehen des Widgets ändern, indem Sie:

  • Überschreiben von Stilen mit CSS.
  • Elemente mit einem Adapter dekorieren
  • Benutzerdefinierte Elemente mit einem Adapter erstellen

Stile mit CSS überschreiben

Das Widget enthält eigenes CSS. Wenn Sie sie überschreiben möchten, verwenden Sie Ancestor-Selektoren, um die Spezifität zu erhöhen:

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

Weitere Informationen finden Sie in der Referenz zu unterstützten CSS-Klassen.

Elemente mit einem Adapter dekorieren

Adapter erstellen und registrieren, um Elemente vor dem Rendern zu ändern In diesem Beispiel wird eine benutzerdefinierte CSS-Klasse hinzugefügt:

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

Registrieren Sie den Adapter während der Initialisierung:

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

Benutzerdefinierte Elemente mit einem Adapter erstellen

Implementieren Sie createSuggestionElement, createFacetResultElement oder createSearchResultElement, um benutzerdefinierte UI-Komponenten zu erstellen. In diesem Beispiel werden die HTML-Tags <template> verwendet:

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

Registrieren Sie den Adapter:

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

Benutzerdefinierte Facettenelemente müssen die folgenden Regeln einhalten:

  • Hängen Sie cloudsearch_facet_bucket_clickable an anklickbare Elemente an.
  • Setzen Sie jede Klasse in ein cloudsearch_facet_bucket_container.
  • Behalten Sie die Bucket-Reihenfolge aus der Antwort bei.

Im folgenden Snippet werden Facetten beispielsweise mithilfe von Links anstelle von Kästchen dargestellt.

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) {
  // ...
}

Suchverhalten anpassen

Sie können die Einstellungen der Suchanwendung überschreiben, indem Sie Anfragen mit einem Adapter abfangen. Implementieren Sie interceptSearchRequest, um Anfragen vor der Ausführung zu ändern. In diesem Beispiel werden Abfragen auf eine ausgewählte Quelle beschränkt:

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

Registrieren Sie den Adapter:

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

Der folgende HTML-Code wird verwendet, um ein Auswahlfeld zum Filtern nach Quellen anzuzeigen:

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>

Mit dem folgenden Code soll die Änderung erkannt, die Auswahl getroffen und die Abfrage falls nötig neu ausgeführt werden.

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

Sie können die Suchantwort auch abfangen, indem Sie interceptSearchResponse im Adapter implementieren.

Versionen anpinnen

  • API-Version: Legen Sie cloudsearch.config/apiVersion vor der Initialisierung fest.
  • Widget-Version: Verwenden Sie gapi.config.update('cloudsearch.config/clientVersion', 1.1).

Wenn nicht festgelegt, sind beide standardmäßig auf 1,0 eingestellt.

So heften Sie das Widget beispielsweise an Version 1.1 an:

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

Suchoberfläche schützen

Befolgen Sie die Best Practices für die Sicherheit von Webanwendungen, insbesondere um Clickjacking zu verhindern.

Debugging aktivieren

Verwenden Sie interceptSearchRequest, um das Debugging zu aktivieren:

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