JavaScript/Tutorials/Formulare/Suchen und Filtern

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
Es wird immer wieder gefragt, wie man eine Suchfunktion in einem HTML-Dokument oder auf einer Webseite realisieren kann.

Dieses Tutorial soll einige Wege aufzeigen und dabei den Unterschied zwischen dem Durchsuchen von Inhalten einerseits und dem Filtern von Suchvorschlägen andererseits herausstellen.

Vorüberlegungen

Eine Suche innerhalb der aktuellen Seite ist in jedem Browser über das Menü oder mit STRG F möglich. Diese Tastenkombination ist vielen Nutzern bereits aus Textverarbeitungen wie MS Word bekannt[1] und Sie sollten unbedingt darauf verzichten, diese Funktion nachzuprogrammieren.

Eine Suche innerhalb einer Website mit mehreren Unterseiten ist entweder bereits in vielen CMS integriert oder muss serverseitig erfolgen. Alternativ kann man auf externe Suchmaschinen zurückgreifen, was Nutzer aber aus dem eigenen Webauftritt wegführt.

Durchsuchen einer bestimmten Website mit duckduckgo
<form role="search" method="GET" action="https://duckduckgo.com/">
	<input name="q" type="search" aria-label="Suche auf selfhtml.org"/>
	<input name="site" type="hidden" value="selfhtml.org"/>
	<button>Suchen</button>
</form>

Duckduckgo erwartet für seine Suchfunktion bestimmte URL Parameter. Das Suchformular erreicht das, indem die Methode GET eingestellt wird und die Eingabefelder passend benannt werden.

q
Der Begriff oder die Begriffe, wonach Duckduckgo suchen soll. Dies ist ein offenes Eingabefeld mit type="search".
site
Der Name der Domain, innerhalb der gesucht werden soll. Für eine site-spezifische Suche soll dieser Name nicht vom Benutzer eingegeben werden und muss auch nicht sichtbar sein, darum ist dieses Feld als type="hidden" angegeben.

Externe Suchmaschinen können natürlich immer nur das indexieren und durchsuchen, was auf Ihren HTML Seiten öffentlich zugänglich ist. Wenn Sie einen login-geschützten Bereich haben, sind Sie darauf angewiesen, eine eigene Suche zu programmieren. Das geschieht dann aber nicht mit JavaScript im Browser, sondern auf Ihrem Server und ist nicht Gegenstand dieses Artikels.

gefilterte Suche mit JavaScript

Auf umfangreichen Seiten mit vielen Informationen ist es eine gute Idee, den Benutzern eine Möglichkeit zu geben, die Informationsmenge an Hand von bestimmten Kriterien zu reduzieren oder zumindest die gewünschten Funktionen deutlich hervorzuheben.

Die im Browser integrierte Suchfunktion kann nach Wörtern suchen und diese hervorheben. Eine Suche dieser Art müssen wir deshalb nicht selbst bauen. Es ist auch ziemlich komplex, in einem mit HTML gespickten Text einen Suchbegriff hervorzuheben, wenn der Text dieses Begriffs durch HTML Markup unterbrochen ist. Für den Selbstbau geeignet ist dagegen ist eine Suchfunktion, die auf der Ebene von HTML Elementen relevante Informationseinheiten hervorhebt, oder weniger relevante Bereiche ausblendet.[2]

Das Script wird …

  • beobachten, was ein Benutzer in die Sucheingabe eingibt,
  • den innerText der durchsuchbaren Elemente filtern,
  • testen, ob der Text den Suchbegriff enthält (.includes() ist hier das A und O!), und
  • die Sichtbarkeit der (übergeordneten) Elemente umzuschalten, je nachdem, ob sie den Suchbegriff enthalten oder nicht

Suchformular

Der Inhalt unserer Webseite besteht aus mehreren article-Elementen, die die Adresse und ein Beispielfoto enthalten:

Vogelparks In Deutschland ansehen …
<article id="de10319">
	<h2>Tierpark Berlin</h2>
	<p>
		<img src="Sagittarius_serpentarius.jpg" alt="Sekretärvogel im Tierpark Belrin">
Am Tierpark 125
10319 Berlin</p>
</article>

<article id="de10787">
<h2>Zoologischer Garten Berlin AG</h2>
<p>
<img src="Glaucidium_perlatum_Berlin_Zoo.jpg" alt="Eule im Zoologischen Garten in Berlin">
Hardenbergplatz 8
10787 Berlin

<br>
<img src="Flamingo_Winter_Zoologischer_Garten_Berlin_cropped.jpg" alt="Flamingos im Winter"></p>
</article>
...

Eine in der Seite integrierte Filterfunktion benötigt JavaScript und kann daher nur ein progressive enhancement sein. Die Benutzeroberfläche für die Filterung sollte daher standardmäßig ausgeblendet sein und nur sichtbar werden, wenn JavaScript ausgeführt wird. Ein <form>-Element ist nicht nötig, aber ein <nav>-Element bietet sich als Container für das Eingabefeld an, weil die Filterung bei der Navigation auf der Seite unterstützt.

Eingabe des Suchbegriffs ansehen …
    <nav id="filter">
        <label for="suchbegriff">Zeige nur Ergebnisse mit </label>
        <input type="search" id="suchbegriff">
    </nav>

Das Suchformular besteht aus einem Input type="search"-Feld, dass durch ein label-Element passend beschriftet ist.

Javascript

die Basis-Version

Die eigentliche Suche wird von der Funktion liveSearch() übernommen:

Suchscript ansehen …
function liveSearch() { 
  let main = document.querySelector("main");
  let alle_artikel = main.querySelectorAll('article');
  let filterbegriff = document.querySelector('#filter input').value.toLocaleLowerCase();
  if (filterbegriff.trim() == "") {
    main.classList.remove("is-filtered");
  }
  else {
    main.classList.add("is-filtered");
    // Die Artikel auf der Seite durchlaufen. 
    for (let artikel of alle_artikel) {
      // Wenn der Suchbegriff als (sichtbarer) Text auftaucht, den Artikel als Treffer markieren
      let relevant = artikel.innerText.toLocaleLowerCase().includes(filterbegriff);
      artikel.classList.toggle('is-relevant', relevant);
    }
  }
}

Die Funktion ermittelt mit querySelectorAll alle <article>-Elemente im <main>-Bereich. Das Ergebnis steht als eine statische NodeList zur Verfügung. Seitdem man auf den Internet Explorer keine Rücksicht mehr nehmen muss, können NodeList-Objekte mit einer for...of-Schleife einfach durchlaufen werden.

Der Filterbegriff wird aus dem Suchfeld (ein input-Element im einem Container mit id="filter") ausgelesen und in Kleinschrift umgewandelt. Dadurch wird eine von Groß-/Kleinschreibung unabhängige Suche ermöglicht.

Vor der eigentlichen Filterung wird geprüft, ob eine Filterbedingung eingegeben wurde. Wenn nicht, wird lediglich die is-filtered Klasse vom main-Element entfernt. Es bleibt dem CSS überlassen, daraus die ungefilterte Darstellung zu erzeugen.

Ist eine Filterbedingung vorhanden, wird im main-Element die is-filtered Klasse gesetzt und die Artikel durchsucht. Diejenigen Artikel, in deren innerText der Suchbegriff gefunden wird, erhalten die is-relevant Klasse. Von den übrigen wird sie entfernt. Die toggle Methode der classList ermöglicht mit ihrem zweiten Parameter ein gezieltes Setzen oder Entfernen einer Klasse.

eine übereifrige Suche bremsen

Damit das Suchscript nicht bereits nach dem ersten eingegebenen Zeichen sucht, bauen wir einen einfachen Debouncer ein. Dazu nutzen wir den SetTimeout-Timer und die Möglichkeit, einen gestarteten Timer mit ClearTimeout wieder zu entfernen.

Verzögerung, bevor liveSearch greift ansehen …
let typingTimer;
let typeInterval = 500;
let searchInput = document.querySelector('#search');

searchInput.addEventListener('input', () => {
    clearTimeout(typingTimer);
    typingTimer = setTimeout(liveSearch, typeInterval);

Mit setTimeout() wird die Funktion liveSearch() erst nach einem bestimmten Zeitraum aufgerufen, den Sie in der Variable typeInterval festlegen können. Tippt der Anwender ein weiteres Zeichen, bevor die Suche begonnen wurde, so wird der bestehende Timer wieder gelöscht.

Alternativtexte berücksichtigen

In der Webseite enthaltene Bilder müssen einen Alternativtext beinhalten, der nicht nur für Screenreader, sondern eben auch für Suchmaschinen und Suchscripte genutzt werden kann. Das soll nun noch ergänzt werden:

<article id="de29664">
<h2>Vogelpark Walsrode</h2>
<p>
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/24/Vogelpark_Walsrode_2012_%28140%29.jpg/640px-Vogelpark_Walsrode_2012_%28140%29.jpg" alt="Tukan im Vogelpark Walsrode">
Am Vogelpark
29664 Walsrode 
<span hidden>Tipp</span>
</p>
</article>

Um neben dem Textinhalt der Textauszeichnungselemente auch den eigentlich „unsichtbaren“ Alternativtext von Bildern zu durchsuchen, muss dieser ebenfalls erfasst werden. Die Suchfunktion wird damit deutlich umfangreicher, deshalb ist die eigentliche Relevanzermittlung für einen Artikel in eine weitere Funktion ausgelagert worden. Das Codebeispiel ist im Übrigen auf den relevanten Teil reduziert worden, den vollständigen Code finden Sie mit "ausprobieren" im Frickl.

Auch in alt-Texten suchen ansehen …
function liveSearch() {
  // ...
  let alle_artikel = main.querySelectorAll('article');
  let filterbegriff = document.querySelector('#filter input').value.toLocaleLowerCase();
  // ...
  for (let artikel of alle_artikel) {
    artikel.classList.toggle('is-relevant', isArticleRelevant(artikel, filterbegriff));
  }
}

// Durchsuchen eines Artikels auf den Filterbegriff
function isArticleRelevant(artikel, filterbegriff) {
  // Wenn der Suchbegriff als (sichtbarer) Text auftaucht, den Artikel als Treffer markieren
  if (artikel.innerText.toLocaleLowerCase().includes(filterbegriff)) {
    return true;
  }
  // Wenn nicht, auch die alt-Texte der Bilder durchsuchen
  let bilder = artikel.querySelectorAll("img");
  for (let bild of bilder) {
    if (bild.alt.toLocalLowerCase().includes(filterbegriff)) {
       return true;
    }
  }
  // Nichts gefunden, nicht relevant
  return false;
}

Ergebnisanzeige

Da sich die Webseite nach jeder Suche ändert, dies z.B. beim Suchbegriff „Berlin“ aber nicht gleich offensichtlich ist, kann es empfehlenswert sein, in einer Status Message die Anzahl der Suchtreffer anzuzeigen [4]

<div role="status">5 Ergebnisse </div>

Combo Box

Eine Combobox ist ein Widget, das aus der Kombination von zwei verschiedenen Elementen besteht:[5]

  1. ein einzeiliges Textfeld und
  2. ein zugehöriges Popup-Element, das dem Benutzer hilft, den Wert des Textfeldes einzustellen. Das Popup-Element kann eine Listbox, ein Grid, ein Baum oder ein Dialog sein. Viele Implementierungen enthalten auch ein drittes optionales Element - eine grafische Schaltfläche neben dem Textfeld, die die Verfügbarkeit des Popup-Fensters anzeigt. Wenn die Schaltfläche aktiviert wird, wird das Popup angezeigt, wenn Vorschläge verfügbar sind.[6]

Im Forum wurde gefragt, wie man ein oben vorgestelltes Suchfeld mit einer Umkreissuche und einer Auto-Vervollständigung von Adressen kombiniert. Hier gibt es mehrere serverseitige Alternativen, die den Umfang dieses Tutorials aber sprengen würden.[7][8]

Weblinks

  1. SELF-Forum: Suchfunktion auf Homepage
  2. css-tricks: In-Page Filtered Search With Vanilla JavaScript von Hilman Ramadhan, Oct 26, 2021
  3. Search Vs. Filter- what is the difference (ux.stackexchange.com)
  4. W3C: Using role=status to present status messages
  5. W3C: role="combobox" WAI-ARIA
  6. W3C: 3.8 Combo Box WAI-ARIA Authoring Practices 1.1
    W3C Working Group Note 14 August 2019
  7. https://wet-boew.github.io/wet-boew-documentation/research/1-datalist-JSON-suggestion.html
  8. HTML Combobox With JavaScript and CSS | Combobox Types & Patterns


Siehe auch