Du hast deinen AdBlocker an?

Es wäre ein Traum, wenn du ihn für t3n.de deaktivierst. Wir zeigen dir gerne, wie das geht. Und natürlich erklären wir dir auch, warum uns das so wichtig ist. Digitales High-five, deine t3n-Redaktion

t3n 17

Webentwicklung für das iPhone – Teil 4: Offline-Datenbank für die eigene Webapplikation

Spricht man im Zusammenhang von Websites oder Webapplikationen über Datenbanken, sind fast immer serverseitige Datenbanksysteme wie MySQL oder Oracle gemeint. Dabei gibt es viele Szenarien, in denen es sinnvoll ist, Daten nicht nur auf einem Server zu speichern, sondern sie auch lokal vorzuhalten – teilweise sogar ausschließlich. Hier kommen Offline-Storages ins Spiel. Wir zeigen, wie man sie für seine eigene iPhone-WebApp nutzt.

Offline-Storages sind Bestandteil von HTML5 und bieten die Möglichkeit, Daten auf dem Client in einer SQLite-Datenbank zu speichern. Diese Daten werden persistent vorgehalten und unterliegen keinem Verfallsdatum. Daher eignen sie sich gut zum Speichern von Benutzereinstellungen, zum Zwischenspeichern von Daten vor dem Senden an einen Server und um Informationen nur einmal vom Server zu übertragen und vorzuhalten, wenn sich der Inhalt serverseitig selten ändert. Da die Datenbank lokal abgelegt ist, wird keine Internetverbindung benötigt, um darauf zuzugreifen.

Als Beispiel dient in diesem Artikel eine fiktive Videodatenbank. Diese verwendet folgenden HTML-Code als Grundgerüst:

HTML-Grundgerüst

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3c.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3c.org/1999/xhtml">
<head>
	<title>Videobestand</title>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
	<meta name="viewport" content="width=320; initial-scale=1.0; user-scalable=0;"/>
	<style type="text/css" media="screen">
		@import "lib/iUI/iui.css";
	</style>
	<style type="text/css" media="screen">
		@import "css/videobestand.css";
	</style>
	<script type="application/x-javascript" xsrc="js/videobestand.js"></script>
	<script type="application/x-javascript" xsrc="lib/iUI/iui.js"></script>
</head>
<body style="overflow:hidden;" onLoad="initDB();">
<div class="toolbar">
	<h1 id="pageTitle"></h1>
	<a id="backButton" class="button" href="#"></a>
</div>
<ul id="home" title="Videobestand" selected="true">
</ul>
</body>
</html>

Listing 1

Das Grundgerüst basiert auf dem iPhone-Userinterface-Framework iUI, das im Verlauf der Serie schon mehrfach zum Einsatz kam. Das eigentliche JavaScript ist in eine externe Datei ausgelagert. Im Body-Bereich befinden sich nur der DIV-Container für die Toolbar am Anfang der Seite und eine ungeordnete leere Liste. Diese Liste soll mit JavaScript gefüllt werden.

Initialisieren der Datenbank

Als erstes müssen Sie die Datenbank initialisieren. Dabei testet das Skript in Listing 2, ob der Browser Offline-Datenbanken unterstützt, indem es versucht, eine Datenbank zu öffnen. Tritt dabei ein Fehler auf, weil die entsprechende Funktion nicht existiert, fängt das Skript den Fehler ab, gibt eine Fehlermeldung aus und bricht an dieser Stelle ab. Im Erfolgsfall wird die Datenbank initialisiert.

Initialisieren der Datenbank

function initDB() {

try {
	if (!window.openDatabase) {
		alert('JavaScript-Datenbanken werden von Ihrem Client nicht unterstützt!');
	} else {
		var shortName = 'videodb';
		var version = '1.0';
		var displayName = 'Videobestand';
		var maxSize = 65536; // max. Größe der Datenbank in bytes
		// Im Erfolgsfall enthält mydb eine Instanz des Datenbank-Objekts
		var mydb = openDatabase(shortName, version, displayName, maxSize);

			createTables(mydb);
		queryDB(mydb);
	}
} catch(e) {
	// Hierher kommt der Code für die Fehlerbehandlung (Error Handling)
	if (e == INVALID_STATE_ERR) {
		// Falsche Datenbank-Version.
		alert("Ungültige Datenbank-Version!");
	} else {
		alert("Unbekannter Fehler "+e+".");
	}
	// return;
}
}

Listing 2

Die Initialisierung beginnt mit dem Erzeugen der Datenbank. Das Skript versucht, die Datenbank zu öffnen. Scheitert dies, weil sie noch nicht existiert, wird sie neu angelegt und geöffnet. Der weitere Zugriff erfolgt dann über das Datenbankobjekt und seine Methoden.

Der „shortName“ identifiziert die Datenbank im System und dient als eindeutiger Bezeichner. Der „displayName“ wird vom Browser angezeigt, wenn es zu Benutzerinteraktionen kommt. Die Variante „version“ spielt im Moment noch keine Rolle und wird erst interessant, wenn die geplante Update-Funktion implementiert ist.

Bis es soweit ist, belassen Sie den Wert am besten auf „1.0“. Der Wert „maxSize“ gibt die zu erwartende Größe der Datenbank an und ermöglicht dem System so eine Ressourcenplanung. Wird mehr Speicher erwartet, gibt das System eine Alert-Box aus, die der Anwender bestätigen muss.

Tabelle anlegen und befüllen

Um auf die Datenbank zuzugreifen, bedienen Sie sich SQL-Queries, die Sie auch von anderen relationalen Datenbanken wie MySQL kennen. Die Funktion, mit der die Queries an die Datenbank geschickt werden, heißt „executeSql“ und ist Teil der Transaktion des Datenbankobjekts.

SQL-Befehle absetzen

function createTables(db) {
	db.transaction(
		function (transaction) {
			transaction.executeSql('SQL-Statement', [], nullDataHandler, errorHandler);
		}
	}
}

Listing 3

Statt SQL-Statement setzen Sie hier das gewünschte SQL-Kommando ein. „NullDataHandler“ ist eine Funktion, die nichts macht. Erwarten Sie einen Rückgabewert, beispielsweise das Ergebnis einer Abfrage, steht hier die Funktion, die das Ergebnis annehmen soll. Die Funktion „errorHandler“ wird nur aufgerufen, wenn ein Fehler bei der Abfrage auftritt.

Anlegen und Befüllen der Tabelle

function createTables(db) {
	db.transaction(
		function (transaction) {
			transaction.executeSql('DROP TABLE IF EXISTS videos;',
															[], nullDataHandler, errorHandler);
				transaction.executeSql('CREATE TABLE IF NOT EXISTS videos (VideoID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT , Name TEXT NOT NULL, Genre TEXT NOT NULL, gesamt INT NOT NULL, verliehen TEXT NULL );',[], nullDataHandler, errorHandler);
				transaction.executeSql('INSERT INTO videos (VideoID, Name, Genre, gesamt, verliehen) VALUES (NULL, "Alien", "SciFi", "12", "11");', [], nullDataHandler, errorHandler);
         transaction.executeSql('INSERT INTO videos (VideoID, Name, Genre, gesamt, verliehen) VALUES (NULL, "Fight Club", "Action", "24", "14");', [], nullDataHandler, errorHandler);
				transaction.executeSql('INSERT INTO videos (VideoID, Name, Genre, gesamt, verliehen) VALUES (NULL, "Keinohrhasen", "Liebeskomödie", "20", "18");', [], nullDataHandler, errorHandler);
				transaction.executeSql('INSERT INTO videos (VideoID, Name, Genre, gesamt, verliehen) VALUES (NULL, "Monster", "Drama", "3", "3");', [], nullDataHandler, errorHandler);
				transaction.executeSql('INSERT INTO videos (VideoID, Name, Genre, gesamt, verliehen) VALUES (NULL, "Serenity", "SciFi", "8", "8");', [], nullDataHandler, errorHandler);
		}
	);
}

function nullDataHandler(transaction, results) { } 

function errorHandler(transaction, error) {
	// error enthält die Fehlermeldung
	alert('ACHTUNG! Es ist ein Fehler aufgetreten: '+error.message+' (Code '+error.code+')');
	return true;
}

Listing 4

Da die Tabelle nun befüllt ist, können Sie sie auch abfragen. Mittels DOM-Scripting werden die Ergebnisse in die Seite eingebaut. Der zugehörige Code sieht wie folgt aus:

Abfrage

function queryDB(db) {
	function dataHandler(transaction, results) {
		var panel = "";
			for (var i=0; i<results.rows.length; i++) {
				var row = results.rows.item(i);
				listElem = document.createElement("li");
				anchorElem = document.createElement("a");
				anchorElem.setAttribute("href","'#"+row['VideoID']+"'");
				anchorElem.appendChild(document.createTextNode(row['Name']));
				listElem.appendChild(anchorElem);
				document.getElementById("home").appendChild(listElem);
					panel = document.createElement("div");
					panel.setAttribute("id",row['VideoID']);
					panel.setAttribute("class","panel");
					panel.setAttribute("title",row['Name']);
					headline = document.createElement("h2");
					headline.appendChild(document.createTextNode("Lokation: " + row['Name']));
					panel.appendChild(headline);
					fieldset = document.createElement("fieldset");
					ptag = document.createElement("p");
					ptag.setAttribute("class","ptext");
					ptag.appendChild(document.createTextNode("Verliehene Videos: " + row['verliehen'] + " von " + row['gesamt']));
			fieldset.appendChild(ptag);
			panel.appendChild(fieldset);
			document.getElementsByTagName("body")[0].appendChild(panel);
		}

	}
	db.transaction(
		function (transaction) {
			transaction.executeSql("SELECT * FROM videos ORDER BY Name;", [], dataHandler, errorHandler);
		}
	);
}

Listing 5

Die abgefragten Daten werden als <li>-Elemente in die Liste eingefügt. Für jedes Element wird ein neuer Container mit der ID des betreffenden Videos angelegt. iUI kümmert sich um die Verknüpfung.

Bitte beachte unsere Community-Richtlinien

Schreib den ersten Kommentar!

Du musst angemeldet sein, um einen Kommentar schreiben zu können.

Jetzt anmelden