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 minimaler HTML- und JavaScript-Code erforderlich. Außerdem werden gängige Funktionen wie Facetten und Paginierung unterstützt. Sie können die Oberfläche auch mit CSS und JavaScript anpassen.

Wenn Sie mehr Flexibilität benötigen, verwenden Sie die Query API. Weitere Informationen Creating a search interface with the Query API.

Suchoberfläche erstellen

Für die Erstellung der Suchoberfläche sind folgende Schritte erforderlich:

  1. Suchanwendung konfigurieren
  2. Client-ID für die Anwendung generieren
  3. Dem Suchfeld und den Suchergebnissen HTML-Markup hinzufügen
  4. Das Widget auf die Seite laden
  5. Widget initialisieren

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 Suchfunktion erstellen.

Client-ID für die Anwendung generieren

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

Projekt konfigurieren

Bei der Konfiguration des Projekts:

  • Wählen Sie als Clienttyp Webbrowser aus.
  • Geben Sie den Origin URI von 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 Web Anwendungen.

HTML-Markup hinzufügen

Für das Widget sind folgende 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 Facet-Steuerelemente

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

Fügen 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>

Geben Sie einen onload-Callback an. 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 verknüpfen.

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

Anmeldeverfahren anpassen

Das Widget fordert Nutzer auf, sich anzumelden, wenn sie mit der Eingabe beginnen. Mit Google Log-in für Websites können Sie das Verfahren anpassen.

Nutzer direkt autorisieren

Mit Über Google anmelden können Sie Anmeldestatus beobachten und 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

Autorisieren Sie die Anwendung vorab für Nutzer in Ihrer Organisation, um die Anmeldung zu vereinfachen. Dies ist auch mit Cloud Identity-Aware Proxy nützlich. Weitere Informationen Weitere Informationen Apps.

Oberfläche anpassen

Sie können die Darstellung des Widgets auf folgende Weise ändern:

  • Stile mit CSS überschreiben
  • Elemente mit einem Adapter dekorieren
  • Benutzerdefinierte Elemente mit einem Adapter erstellen

Stile mit CSS überschreiben

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

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

Referenz zu unterstützten CSS Klassen

Elemente mit einem Adapter dekorieren

Erstellen und registrieren Sie einen Adapter, um Elemente vor dem Rendering 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 HTML <template> Tags 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();

Für benutzerdefinierte Facet-Elemente gelten folgende Regeln:

  • Fügen Sie cloudsearch_facet_bucket_clickable zu klickbaren Elementen hinzu.
  • Umschließen Sie jeden Bucket mit einem 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

Überschreiben Sie die Einstellungen der Suchanwendung, 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 keine Version festgelegt ist, wird standardmäßig 1.0 verwendet.

So pinnen Sie das Widget beispielsweise an Version 1.1:

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

Suchoberfläche schützen

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