Mit HTML5 kommen viele neue Features auf den Client, unteranderem auch die Möglichkeit per JavaScript lokal Daten abzuspeichern in Form von Variablen oder SQLite-Datenbanken.
Das Erstellen einer lokalen SQLite-Datenbank macht vorallem dann sinn, wenn der User auch offline weiterhin Daten abrufen können soll, wie z.B. in mobilen Web Applikationen. Einen weiteres Ziel kann es sein die Lade-Zeit zu verkürzen indem man Datenbankzeilen lokal cached und bei erneutem Besuch einer Website / Applikation nur auf neue Datenbank-Einträge anfragt. Dieser Ablauf kann dann Asynchron im Hintergrund geschehen, während der Benutzer schon Ergebnisse sehen kann.
Die gängigen Browser wie Chrome, Safari und Firefox (erst in Version 4.0) unterstützen diese neue Technik, aber vor allem profitieren mobile Browser schon von ihr.
Im Folgenden werde ich eine kleine Datenbankklasse vorstellen, die es erleichtert lokale SQLite Datenbanken mit JavaScript zu verarbeiten.
DB = function( dbName, dbVersion, dbDescription, dbSize ) {
this.db_name = dbName;
this.db_version = dbVersion;
this.db_description = dbDescription;
this.db_size = dbSize;
this.db_disabled;
this.db_connection;
this.instance_id;
this.instance;
this.db_structure = new Array();
this.constructor = function() {
// wir prüfen ob openDatabase vom Browser unterstützt wird
this.db_disabled = ( window.openDatabase ? false : true );
}();
// connected die Klasse mit der Datenbank
this.connect = function() {
// wenn der Browser es nicht unterstützt wird die funktion vorzeitig beendet
if( this.db_disabled )
return false;
// Verbindungsaufbau
this.db_connection = window.openDatabase( this.db_name, this.db_version, this.db_description, this.db_size );
if( this.db_connection ) this._fetchStructure();
return this.db_connection;
}
// zieht sich die Struktur der Datenbank
// um später abfragen wie tableExists synchron auszuführen
// da openDatabaseSync nicht von allen Browsern unterstützt wird
this._fetchStructure = function() {
// setzen einer instance Variable um _fetchStructurHandler nicht im "this" Kontext zu starten
var instance = this;
this.db_connection.transaction(function( tx ) {
tx.executeSql( "SELECT * FROM sqlite_master", [], function(tx,rs) {
instance._fetchStructurHandler(tx,rs);
}, function( tx, err ) {
alert( err.message );
});
});
}
// durchläuft den Ergebnis-Array der Struktur-Abfrage
this._fetchStructurHandler = function( tx, rs ) {
for( var x = 0; x < rs.rows.length; x++ ) {
if( rs.rows.item(x).tbl_name )
this.db_structure.push( rs.rows.item(x).tbl_name );
}
this.connected();
}
// gibt true wieder wenn eine Verbindung zur Datenbank besteht
this.isConnected = function() {
return ( this.db_connection ? true : false );
}
// führt einen Query aus
this.query = function(queryString, queryVariables, callbackSuccess, callbackFailed ) {
this.db_connection.transaction( function( tx ) {
tx.executeSql( queryString, queryVariables, callbackSuccess, callbackFailed );
});
}
// prüft nach ob eine Datenbank-Tabelle vorhanden ist
this.tableExists = function( tableName ) {
for( var i = 0; i < this.db_structure.length; i++ ) {
if( this.db_structure[i] == tableName ) return true;
}
return false;
}
// kann als listener belegt werden und wird ausgeführt sobald die Verbindung besteht
// und die Struktur abgespeichert wurde
this.connected = function(){ }
}
Nun ein Beispiel wie mit dieser Datenbank-Klasse gearbeitet werden kann.
<!DOCTYPE html>
<html>
<head>
<title>html5 database</title>
<script type="text/javascript" src="database.class.js"></script>
</head>
<body>
<div id="message">
</div>
<div id="test">
</div>
<div >
<input type="text" value="title" id="F_title" /><br />
<textarea id="F_text">Text</textarea><br />
<input type="submit" value="speichern" onclick="F_submit()" />
</div>
<script type="text/javascript">
function F_submit() {
var title = document.getElementById('F_title').value;
var text = document.getElementById('F_text').value;
if( !d.isConnected() ) {
alert("no database connection");
return false;
}
d.query("INSERT INTO test (name,text) VALUES (?,?)", [ title, text ], function(tx,rs){
document.getElementById('message').innerHTML = "nachricht eingetragen";
}, function(tx,err){ alert(err.message); });
return false;
}
var d;
window.onload = function() {
d = new DB("dbt", "", "my app", 1024*1024);
d.connected = function() {
if( d.tableExists("test") ){
d.query( "SELECT * FROM test", [],
function(tx,rs) {
var td = document.getElementById('test');
var it;
for( var x = 0; x < rs.rows.length ; x++ ) {
it = rs.rows.item(x);
td.innerHTML += it.name +" <br />"+it.text+"<hr />";
}
}, function(tx, err) {
alert(err.message);
});
} else {
d.query("CREATE TABLE test ( `name` TEXT, `text` TEXT, PRIMARY KEY (`name`) )", [], function(tx,rs) {
document.getElementById('message').innerHTML = "table erstellt";
}, function( tx, err) {
document.getElementById('message').innerHTML = "Fehler beim erstellen: " + err.message;
});
}
};
d.connect();
}
</script>
</body>
</html>
