Benutzer:Rolf b/WebStorage

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Neufassung von JavaScript/Web_Storage

Die Web Storage API ist ein Teil der HTML Spezifikation und ermöglicht es, im Browser Daten so zu speichern, dass sie auch nach dem Verlassen einer Seite noch zur Verfügung stehen. Man unterscheidet zwischen Local Storage, der auch nach dem Schließen des Browsers erhalten bleibt, und Session Storage, der nach dem Schließen eines Tabs gelöscht wird.

Beide Speicherorte sind in über Eigenschaften des window-Objekts erreichbar, die in allen aktuellen Browsern verfügbar sind und sogar schon im Internet Explorer bekannt waren:

window.localStorage
liefert das Storage-Objekt des Local Storage
window.sessionStorage
liefert das Storage-Objekt des Session Storage

Beide Speicherorte sind nur auf dem window-Objekt (bzw. im globalen Scope eines Browser-Dokuments) zu finden, in Workern dagegen nicht.

Im Zusammenhang mit Web Storage findet man auch das Storage API. Dieses beschäftigt sich mit dem Speichermanagement, das den zuvor genannten Speichermöglichkeiten zu Grunde liegt, und ist ziemlich abstrakt. Wir werden es in diesem Artikel nur insoweit streifen, wie es zum Verständnis von Web Storage erforderlich ist.

In der Storage Spezifikation finden sich Quota (Größenbeschränkungen) für local und session storage von jeweils 5 MeBiByte (5 × 220 Bytes). Wenn Sie diese Quota überschreiten, wird der Browser eine DOMException auslösen.

Das Storage Objekt

Der Local Storage und der Session Storage werden durch ein Storage-Objekt realisiert. Der Browser stellt für jeden Origin ein Local Storage Objekt bereit, und für jeden Browser-Tab, in dem eine Seite dieses Origins geöffnet wird, ein Session Storage Objekt. Diese beiden Objekte sind unabhängig voneinander.

Pro Origin bedeutet, dass sich alle HTML Dokumente, bei denen die URL-Anteile Schema, Hostname und Port übereinstimmen, einen Local Storage teilen. Wenn Sie auf einem geöffneten Browser-Tab zwischen mehreren Seiten wechseln, bei denen der Origin übereinstimmt, ist auch der Session Storage der gleiche. Wenn Sie eine Seite des gleichen Origin in einem anderen Tab öffnen, erhalten Sie einen anderen Session Storage. Wenn Sie den Tab schließen, wird der Session Storage gelöscht.

Sie können Storage-Objekte dazu benutzen, Daten in Form von Schlüssel-Wert (key-value) Paaren abzulegen. Sowohl Schlüssel als auch Wert müssen eine Zeichenkette sein. Das Storage-Objekt bietet dazu folgende Methoden an. Ausführlichere Informationen und einfache Beispiele finden Sie im zugehörigen Referenzartikel zum Storage-Objekt.

getItem(key)
Wert zum Schlüssel lesen.
setItem(key, value)
Wert unter dem angegebenen Schlüssel speichern
length
Diese Eigenschaft liefert die Anzahl der im Storage abgelegten Schlüssel
key(n)
Gibt den Namen des n-ten Schlüssels zurück, unter dem Daten abgelegt sind
removeItem(key)
Entfernt den Eintrag zum übergebenen Schlüssel
clear()
Löscht alle Einträge

Wenn Sie mit setItem einen Wert speichern, finden Sie den verwendeten Key danach auch als Eigenschaft des Storage-Objekts vor. In der HTML Spezifikation ist auch vorgesehen, dass der Aufruf von storage.setItem(key, value) gleichbedeutend sein soll mit storage[key] = value. Dieses „Feature“ ist aber eine ziemlich schlechte Idee. Stellen Sie sich vor, Sie möchten einen Wert unter dem Schlüssel "length" oder "clear" speichern. Wenn Sie das mit storage['clear'] = 'Hallo selfhtml' tun, dann haben Sie die vom Storage-Prototypen bereitgestellte clear-Methode verdeckt. Mit storage.setItem('clear', 'Hallo') passiert Ihnen das nicht.

Empfehlung: Verwenden Sie immer die Zugriffsmethoden, um Storage-Elemente zu lesen, zu schreiben oder zu löschen, um nicht mit geerbten Namen von Eigenschaften oder Methoden kollidieren zu können.
Beachten Sie: Wenn Sie als Schlüssel oder Wert etwas angeben, das kein String ist, konvertiert das API diesen Wert in einen String. Dazu verwendet es die toString()-Methode, die jedes JavaScript-Objekt besitzt. Aus einem Array entsteht so eine kommaseparierte Liste, aus einem Objekt einfach nur "[object Object]". Verwenden Sie JSON.stringify(), um Arrays oder Objekte in einen JSON-String zu konvertieren, den Sie nachher mit JSON.parse() wieder in ein Array oder Objekt umwandeln können.

Speicherüberlastung

Man spricht von Speicherüberlastung (storage pressure), wenn die Gesamtmenge aller Local Storage Daten, die sich im Browser ansammeln, die vom Browserhersteller vorgesehene Höchstmenge überschreitet. Beispielsweise könnte ein Browserhersteller festlegen, dass sein Browser keine Benutzerdaten mehr speichern soll, wenn die Festplattte, auf der sie liegen, zu mehr als 90% gefüllt ist.

Um die Speicherüberlastung zu beheben, kann der Browser den Local Storage von einigen Origins verwerfen. Die HTML Spezifikation besagt, dass er das so tun soll, dass der Einfluss auf den Benutzer möglichst gering ist - konkret bedeutet das, dass der Local Storage der am längsten nicht mehr besuchten Origins verworfen wird.

Ein solches Verwerfen kann unangenehme Folgen haben. Deshalb kann eine Webseite vom Browser verlagen, die lokalen Daten ihres Origins bei Speicherüberlastung nicht zu entfernen. Dazu dient die Methode persist, die von dem StorageManager Objekt bereitgestellt wird, das Sie über window.navigator.storage erhalten.

Hinweis:
Die Spezifikation erwähnt nicht, wie man den Persistenzmodus wieder löscht. Überlegen Sie gut, ob die lokal gespeicherten Daten Ihrer Seite tatsächlich auch bei Speicherüberlastung erhalten bleiben müssen.

Datensicherheit

Wenn Sie personenbezogene Daten speichern, müssen Sie die Benutzer immer darüber informieren, was Sie speichern und warum Sie es tun. Sie müssen dem Benutzer die Möglichkeit geben, die Speicherung abzulehnen, und es muss auch die Möglichkeit geben, diese Daten zu löschen, wenn der Benutzer es fordert.

Ohne Einwilligung speichern dürfen Sie Daten, die nicht personenbezogen sind, oder ohne die Sie die vom Benutzer gewünschte Leistung nicht erbringen können. Soweit solche Daten personenbezogen sind, müssen Sie darüber aber informieren und müssen dem Benutzer die Möglichkeit geben, auf die Datenspeicherung und damit auf die Dienstleistung zu verzichten. Eine Speicherungserlaubnis ohne Rückfrage gibt es auch beim sogenannten „legitimen Interesse“ des Dienstanbieters - einen Begriff, den wir hier im Wiki nicht detailliert auslegen können.

Wenn Sie personenbezogene Daten, beispielsweise mit PHP, auf Ihrem Server speichern, hat das den Vorteil, dass Sie diese Daten auch verarbeiten können, ohne dass der Benutzer online ist. Und sie stehen dem Benutzer von überall zur Verfügung. Für Kundendaten und den Warenkorb eines Webshops ist das kaum vermeidbar. Es bedeutet aber auch, dass Sie zügig aktiv werden müssen, wenn Sie eine Löschforderung bekommen. Für eine serverseitige Speicherung benötigen Sie auch eine Benutzerverwaltung mit sicherem Login, und natürlich eine DSGVO-konforme Arbeitsweise.

Web Storage hat hier den Vorteil, dass die Daten auf dem Computer des Nutzers bleiben und er die Kontrolle über seine Daten behält. Aber sie können eben auch nur auf genau dem Computer verarbeitet werden, wo sie gespeichert sind, bzw. Ihre Website muss die Daten, wenn sie am Server benötigt werden, dorthin übertragen. Hinzu kommt, dass die im Browser gespeicherten Daten bei Speicherüberlastung gelöscht werden können, dass sie beim Inkognito-Browsen gar nicht gespeichert werden und dass ein unbedarfter Anwender möglicherweise "Cookies und sonstige Website-Daten" löscht und damit alles weg ist.

Prüfen des Inhalts von Storage-Objekten

Sie können die Storage-Objekte der dargestellten Seite in den Entwicklungswerkzeugen Ihres Browsers anschauen.

Chrome
Auf dem Tab Anwendung (oder Applikation) finden Sie links die Rubriken Lokaler Speicher und Sitzungsspeicher.
Firefox
Auf dem Tab Web-Speicher finden Sie links die Rubriken Local Storage und Session Storage,

enthalten ein Tab "Anwendung" (Chrome) oder "Web-Speicher" (Firefox)

In diesen Rubriken finden Sie die Origins, die im aktuellen Dokument verwendet werden. Das kann mehr als einer sein, wenn ein iframe verwendet wird, in dem ein Dokument aus einem anderen Origin angezeigt wird. Klicken Sie in der gewünschten Rubrik den Origin an, dessen Daten Sie sehen wollen, und Sie erhalten eine Auflistung aller dort gespeicherten Schlüssel-Wert Paare.

Sollte einer der Einträge ein im JSON-Format gespeichertes Objekt beinhalten, zeigt Ihnen Firefox den Eintrag rechts neben der Liste als Objekt an. Bei Chrome finden Sie diese Anzeige unter der Liste.

In dieser Auflistung können Sie Einträge löschen, Schlüsselnamen oder Werte verändern und auch neue Einträge anlegen. Zum Anlegen müssen Sie in Chrome unter den vorhandenen Einträgen die rechte Maustaste drücken, bei Firefox auf einem der vorhandenen Einträge oder alternativ das + Icon rechts oben.

Beispiel: Todo-Liste mit localStorage

Arunkumar Gudelli hat eine localStorage-Anwendung für eine Linksammlung geschrieben, die hier in abgewandelter Form ToDos verwaltet.[1] Wir werden den Quellcode nicht in den Artikel kopieren. Sie können ihn hier abrufen: Beispiel:JS-WebStorage-TodoList.html.

HTML

Das HTML ist recht einfach gehalten und besteht im Wesentlichen aus einem kleinen Eingabeformular für neue Todo-Einträge. Ein solcher Eintrag ist einfach nur ein kurzer Text. Darüber hinaus gibt es noch zwei Buttons, einer zum Anlegen des neuen Eintrags und einer zum Löschen der Liste.

Das verwendete JavaScript soll adaptiv und wiederverwendbar sein, deshalb sucht es die HTML Elemente, die es benötigt (das Eingabefeld und die beiden Buttons), an Hand einer Klasse in dem <form>-Element. Deshalb sind diesen Elementen die Klassen todo-entry, todo-create und todo-clear<code> zugeordnet.

Die eigentliche Todo-Liste wird in einem <code><ul>-Element dargestellt. Dieses befindet sich zusammen mit dem Hinweisparagraphen zum Löschen von Einträgen in einer section, so dass das komplette <main>-Element dann als Grid layoutet werden kann.

Der Inhalt der Todo-Liste wird vom JavaScript-Teil erzeugt. Pro Todo-Eintrag entsteht ein <li>-Element und darin befindet sich ein <button>-Element mit dem Text des Todo. Der Button ist deshalb da, weil ein Todo-Eintrag durch einen Klick gelöscht werden können soll.

CSS

Das CSS verwendet ein Grid, um das <main>-Element zu layouten. Darüber hinaus wird die Todo-Liste etwas aufgehübscht. Die <button>-Elemente der Todo-Liste werden von ihrem Rand befreit, statt dessen wird der Rand durch die Hintergrundfarbe der Liste sowie durch den Abstand der Buttons voneinander dargestellt. Auf diese Weise haben die Buttons Platz, einen Fokus-Rahmen anzuzeigen, der beim Durchlaufen der Liste per Tabulatortaste angezeigt wird. Der erste und letzte Button werden darüber hinaus noch oben bzw. unten abgerundet.

Wenn die Liste leer ist, setzt das JavaScript darauf die Klasse empty. Das ist nicht zwingend nötig, man könnte auch mit der Pseudoklasse :empty arbeiten, aber diese Pseudoklasse hat leichte Abweichungen im Browserverhalten, wenn ein Element Whitespace enthält. Das CSS im Beispiel verwendet die empty-Klasse, um bei einer leeren Liste ein ::before-Element mit dem Inhalt "Liste ist leer" anzuzeigen.

JavaScript

Das Frickl-Labor im Selfwiki ist leider ziemlich alt und hat einige Defizite. Deswegen können wir das Script nicht als ECMAScript-Modul einbinden. Statt dessen wird eine Funktion benutzt, um alle Bausteine der Todo-Liste zu kapseln, und in einem DOMContentLoaded-Handler wird die Todo-Liste mit dem Eingabeformular und der Anzeigeliste verknüpft und initialisiert:

 document.addEventListener("DOMContentLoaded", function() {
    todoListe(document.forms[0], document.querySelector(".todo-list"));
 });

Diese Einbindung ist natürlich speziell für unser minimales HTML gemacht.

Initialisierung

Die todoListeController-Funktion erwartet als ersten Parameter einen Verweis auf das HTMLFormElement mit dem Eingabeformular. Das ist in unserem HTML mit document.forms[0] am einfachsten getan. Der zweite Parameter muss das HTMLUListElement oder HTMLOListElement sein, das die <li>-Elemente der Todo-Liste aufnehmen soll. Als dritter Parameter kann ein Optionen-Objekt übergeben werden, womit man die vom Script verwendeten Klassennamen überschreiben kann, und den Präfix-Text für die id-Attribute der <li>-Elemente sowie den Schlüssel, unter dem die Liste im localStorage gespeichert wird, setzen. Die Defaultwerte dieser Optionen sind im Objekt defaultOptions gespeichert. Dieses Objekt wird zu Beginn als Prototyp des eigentlichen configuration-Objekts gesetzt, so dass sich seine Einträge dorthin vererben. Danach werden die gesetzten Optionen - sofern im defaultOptions-Objekt bekannt - übertragen:

 let configuration = Object.create(defaultOptions);
 for (let opt in options) {
   if (defaultOptions.hasOwnPropertyName(opt))
     configurations[opt] = options[opt];
 } 

Das Schöne an for..in ist, dass es für undefined, null oder skalare Werte einfach nichts tut und bei Arrays oder Strings die Indexpositionen durchläuft, die es aber in den defaultOptions nicht gibt. Eine besondere Abfrage, ob ein korrektes options-Objekt übergeben wurde, entfällt damit.

Die todoListeController-Funktion prüft dann noch, ob ein Form und ein <ul> oder <ol>-Element als Liste übergeben wurden, sucht sich die benötigten HTML Elemente aus dem Form und registriert dann als Eventhandler - einen submit-Handler für das Form (der Hinzufügen-Button ist der submit-Button dieses Forms). Damit kann ein Todo-Element sowohl durch den Button wie auch durch Drücken der Enter-Taste gespeichert werden. - einen click-Handler für den "Alles löschen" Button - einen click-Handler auf dem Listen-Element, bei dem alle Klicks auf die Buttons der Todo-Liste landen werden.

Danach wird die Todo-Liste aus dem localStorage geladen, die Einträge in die HTML Liste übertragen, der Fokus auf das Eingabefeld gesetzt und die Liste ist bereit.

Hilfsfunktionen

Die eigentliche Arbeit erfolgt in einigen Helferfunktionen, die im Folgenden beschrieben werden. Zu beachten ist, dass die Variablen todoListe oder domListe von diesen Funktionen bei Bedarf verwendet, aber nicht als Argument übergeben werden. Die Helferfunktionen sind Teil des Aufrufkontexts der todoListeController()-Funktion und bleiben intern darin, deswegen ist das unproblematisch.

ladeTodoListe
Holt die Todo-Liste aus dem Local Storage, übersetzt den JSON-String des Local Storage in die Array-Darstellung und speichert sie in der Variablen todoListe ab. Falls im Local Storage kein Wert vorliegt, wird einfach ein leeres Array gespeichert.
speichereTodoListe
Konvertiert das todoListe-Array in einen JSON String und schreibt ihn in den Local Storage. Falls im todoListe-Array keine Einträge stehen, wird der Local Storage-Eintrag gelöscht.
erzeugeTodo
Erzeugt einen Todo-Eintrag aus dem aktuellen Timestamp und einem Text. Falls der Text leer ist, wird null zurückgegeben (unzulässige Eingabe)
todoInsDOM
Erzeugt aus einem Todo-Eintrag ein <li>-Element im DOM mit dem passenden HTML-Inhalt und hängt es an die vorhandene Liste an.
markiereLeereListe
Prüft, ob todoListe Einträge enthält. Ist sie leer, wird auf der HTML Liste die Klasse empty gesetzt, andernfalls wird die Klasse entfernt. Mit dieser Klasse sollen die möglichen Ungenauigkeiten und Browserunterschiede der Pseudoklasse :empty umgangen werden.
isList
Dient während der Initialisierung zur Überprüfung, ob der übergeben Listencontainer zulässig ist.

Eventbehandlung

Die Hauptarbeit der Todo-Liste erfolgt nun in den Eventhandler-Funktionen, die von der Initialisierung registriert wurden.

Die Funktion ladeTodoListe() liest dafür einfach den entsprechenden localStorage-Eintrag aus. Sämtliche Todo-Einträge sind als ein JSON-codiertes Array in einem localStorage-Eintrag gespeichert. Die Funktion muss nur prüfen, ob der Eintrag da ist. Wenn ja, decodiert sie das Array, andernfalls liefert sie ein leeres Array.

Zum Übertragen ins DOM legt die Funktion todoInsDOM() ein für einen Todo-Eintrag <li>-Element an, gibt ihm eine ID, die sich aus dem ID-Präfix der Konfiguration und der ID des Todo-Eintrags zusammensetzt, und erzeugt darin dann einen Button, dessen Text der Todo-Eintrag ist. Eine komplexere Todo-Liste müsste hier sicherlich ein umfangreicheres Template verwenden, aber darauf soll in diesem Beispiel verzichtet werden.

Sobald die Liste geladen ist, sind drei Funktionen möglich, für die jeweils eine Funktion bereitsteht:

  • todoHinzufügen(): submit-Eventhandler für das Eingabeform, legt einen neuen Eintrag an
  • todoEntfernen(): click-Eventhandler des Buttons im Todo-Eintrag, entfernt den Eintrag
  • todoListeLöschen(): click-Eventhandler des "alles Löschen" Buttons, leert die Liste im DOM und im Arbeitsspeicher, und entfernt den localStorage Eintrag.

Diese drei Funktionen machen häufigen Gebrauch von kleinen Funktionen, die nicht viel tun, aber einen sprechenden Namen haben. Auf diese Weise dokumentiert der Code sich selbst. Diese Funktionen sind:

  • ladeTodoListe: Befüllt die Variable

In todoHinzufügen() muss zunächst die preventDefault-Methode auf dem submit-Eventobjekt aufgerufen werden, damit der Browser das Form nicht zum Server schickt. Als nächstes wird versucht, einen neuen Eintrag für das todoListe-Array zu erzeugen - das scheitert, wenn der Text leer ist. Dieser Eintrag wird dann mit den vorhandenen Listeneinträge verglichen, um Duplikate in der Liste zu vermeiden. Ist der Eintrag in Ordnung, wird er an die todoListe im Speicher und an die Liste im DOM angehängt und die Liste im Speicher in den localStorage geschrieben. Für ein kleines Beispiel kann man so vorgehen - es wäre anders, wenn Sie mit Listen hantieren, die 1000 Einträge oder mehr haben. Zum einen könnte das für den Local Storage zu viel werden, zum anderen müsste man dann messen, ob der stringify-Aufruf nicht zu lange dauert und bei Bedarf eine andere Speicherstrategie entwickeln. Zum Abschluss der Funktion wird das Eingabefeld gelöscht und bekommt wieder den Fokus, um den nächsten Eintrag vornehmen zu können.

Die todoEntfernen()-Funktion wird als click-Handler des <button>-Elements aufgerufen, in dem der Text zum Todo-Eintrag steht. Es muss also ein <li>-Element als Elternelement geben, das mit einem closest('li')-Aufruf ermittelt werden kann. Zur Sicherheit wird noch geprüft, ob die id dieses Listeneintrags auch mit dem konfigurierten ID-Präfix beginnt, das kann aber eigentlich nur bei einem Programmierfehler passieren. Aus dem id-Attribut des Listeneintrags wird dann die interne ID des Todo-Eintrags abgeleitet. Das <li>-Element kann nun schon aus dem DOM gelöscht werden. Um den Todo-Eintrag aus dem Array im Speicher zu entfernen, gibt es verschiedene Wege. Das Array ist klein, darum wird hier einfach die filter()-Methode genutzt, um nur die Einträge zu behalten, die nicht die gelöschte id haben. Zum Abschluss wird die Todo-Liste wieder im localStorage abgelegt


ToDo-Liste ansehen …
function todoListe(form, list, options) {
	let configuration = Object.create(options ?? Object.prototype);
	configuration.todoEntryClass ??= "todo-entry";
	configuration.todoCreateClass ??= "todo-create";
	configuration.todoClearClass ??= "todo-clear";
	configuration.todoStorageName ??= "todoListe";

	if (!(form instanceof HTMLFormElement) || !(isList(list)) )
		throw new Error("Eingabe-Form und Anzeigeliste fehlen");

	const entryField = form.querySelector(`input[type=text].${configuration.todoEntryClass}`);
	const createButton = form.querySelector(`button.${configuration.todoCreateClass}`);
	const clearButton = form.querySelector(`button.${configuration.todoClearClass}`);
	if (!entryField || !createButton || !clearButton)
		throw new Error("Eingabeformular der Todo-Liste inkorrekt oder unvollständig");

	createButton.addEventListener("click", toDoHinzufügen);
	clearButton.addEventListener("click", toDoListeLöschen);

	const todoListe = ladeTodoListe(configuration.todoStorageName);
	todoListe.forEach(eintrag => todoCreate(eintrag.id, eintrag.text));

	function isList(element) {
		return element && (element instanceof HTMLUListElement || element instanceof HTMLOListElement);
	}

button.addEventListener('click', toDoHinzufügen);
	const clearButton = document.getElementById('loeschen');
	clearButton.addEventListener('click', allesLöschen);
	const eintraegeArray = ladeEinträge();
	for (var i = 0; i < eintraegeArray.length; i++) {
		var aufgabeNr = eintraegeArray[i];
		var value = JSON.parse(localStorage[aufgabeNr]);
		insDOMschreiben(aufgabeNr, value);
	}	
}
function ladeEinträge() {
	var eintraegeArray = localStorage.getItem('todoListe');
	if (!eintraegeArray) {
		eintraegeArray = [];
		localStorage.setItem('todoListe', JSON.stringify(eintraegeArray));
	} else {
		eintraegeArray = JSON.parse(eintraegeArray);
	}
	return eintraegeArray;
}

function ToDoHinzufügen() {
	var eintraegeArray = HolEinträge();
	var value = document.getElementById('eingabe').value;
	if(value!='')
	{
	var currentDate = new Date();
	var aufgabeNr = 'aufgabe_' + currentDate.getTime()	
	var aufgabeText = {'value': value};
	localStorage.setItem(aufgabeNr, JSON.stringify(aufgabeText));	
	eintraegeArray.push(aufgabeNr);
	localStorage.setItem('eintraegeArray', JSON.stringify(eintraegeArray));
	insDOMschreiben(aufgabeNr, aufgabeText);
	document.getElementById('eingabe').value=' ';
	}
	else
	{
	alert('Bitte geben Sie etwas ein!');
	}
}

function toDoLöschen(e) {
	var aufgabeNr = e.target.id;
	var eintraegeArray = HolEinträge();
	if (eintraegeArray) {
		for (var i = 0; i < eintraegeArray.length; i++) {
			if (aufgabeNr == eintraegeArray[i]) {
				eintraegeArray.splice(i,1);
			}
		}
		localStorage.removeItem(aufgabeNr);
		localStorage.setItem('eintraegeArray', JSON.stringify(eintraegeArray));
		ausDOMentfernen(aufgabeNr);
	}
}

function insDOMschreiben(aufgabeNr, ItemObj) {
	var eintraege = document.getElementById('eintraege');
	var eintrag = document.createElement('li');
	eintrag.setAttribute('id', aufgabeNr);
    eintrag.innerHTML = ItemObj.value;
	eintraege.appendChild(eintrag);
	eintrag.onclick = toDoLöschen;
}

function ausDOMentfernen(aufgabeNr) {
	var eintrag = document.getElementById(aufgabeNr);
	eintrag.parentNode.removeChild(eintrag);
}

function allesLöschen() {
	localStorage.clear();
	var ItemList = document.getElementById('eintraege');
	var eintraege = ItemList.childNodes;
	for (var i = eintraege.length-1; i >= 0; i--) {
		ItemList.removeChild(eintraege[i]);
	}
	var eintraegeArray = HolEinträge();
}
Nach dem Laden der Seite wird die Funktion init() aufgerufen, die sich erst mit HolEinträge() die schon bestehenden Einträge aus dem WebStorage holt und in ein array eintraegeArray schreibt.

Mit der Funktion insDOMschreiben(aufgabeNr, ItemObj) wird die Liste mit der id eintraege durch document.createElement('li') mit einem neuen Listeneintrag erweitert. Er erhält als id einen Zeitstempel und als Inhalt mittels innerHTML den gespeicherten Text.

Wenn Sie jetzt neuen Text in das Eingabefeld eingeben und auf den Button klicken, wird die Funktion ToDoHinzufügen() aufgerufen. Wenn im Eingabefeld Text vorhanden war, erhält dieser einen Zeitstempel und wird mit diesem und dem Inhalt der Eingabe, die mit JSON.stringify in eine Zeichenkette umgewandelt wurde, abgespeichert.

Durch einen Klick auf Listenelemente können Sie einzelne Listenelemente mit localStorage.removeItem(aufgabeNr) löschen. Ein Klick auf den Löschen-Button löscht die gesamte gespeicherte Liste mit localStorage.clear().

Alternativen

Cookies

Auch Cookies werden dauerhaft im Browser gespeichert. Sie unterscheiden sich von den Storage-Objekten, Caches und IndexedDB in den folgenden Punkten:

  • Cookies dienen vor allem dazu, vom Server vorgegebene Werte zu speichern
  • Cookies haben nicht wirklich ein API, sie werden mit Hilfe von speziellen Zeichenketten über die cookie-Eigenschaft des Document-Objekts verwaltet
  • Die Sichtbarkeit von Cookies kann auf einen bestimmten Ressourcenpfad einer Domain begrenzt werden. Die Storage-Objekte sind immer für die ganze Domain sichtbar
  • Ein Cookie hat eine vorgegebene Lebensdauer
  • Je nach Browser-Einstellung und Response-Headern einer Seite können Ressourcen, die von Drittanbietern hinzugeladen werden, Cookies dieser Drittanbieter übertragen
  • Cookies werden bei Server-Requests mit zum Server übertragen und könnn vom Server verändert werden. Größere Datenmengen in Cookies führen zu einer deutlichen Erhöhung des übertragenen Datenvolumens und bremsen damit eine Webseite aus
Beachten Sie: Datensparsamkeit und Datensicherheit
Sowohl Cookies wie auch andere dauerhafte Datenspeicher dürfen nur verwendet werden, wenn entweder ein berechtigtes Interesse an der Speicherung begründet werden kann, oder der Webseitenbesucher sein Einverständnis zur Speicherung gibt. Man spricht hier zwar regelmäßig von der Cookie-Richtlinie, die EU Datenschutzgrundverordnung gilt aber weltweit und für jegliche personenbezogene Daten, egal ob sie im Browser oder auf einem Server gespeichert werden.

Cache Storage und IndexedDB

Es gibt noch zwei weitere Techniken, um Daten im Browser abzulegen. Diese sind auch in Workern verfügbar und haben jeweils eine eigene Spezifikation und eine eigene Programmierschnittstelle.

  • Das CacheStorage Objekt, das Teil des ServiceWorker API ist und über die caches-Eigenschaft des globalen Objekts erreicht werden kann. Der CachedStorage ist zum Zwischenspeichern von Ressourcen gedacht, die von einem Server geladen wurden, und eignet sich nicht als eigenständiger Datenspeicher.
  • Das IndexedDB API, das über die indexedDB Eigenschaft des globalen Objekts verfügbar ist. Es wurde für das clientseitige Speichern und Verarbeiten größerer Datenmengen entwickelt und bietet allen Komfort einer Datenbank.

Weblinks

  1. Arunkumar Gudelli: HTML5 Web Storage API Example