Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

AutoSave für AJAX-Formulare Timo Holzherr

Ähnliche Präsentationen


Präsentation zum Thema: "AutoSave für AJAX-Formulare Timo Holzherr"—  Präsentation transkript:

1 AutoSave für AJAX-Formulare Timo Holzherr
AJAX in ACTION 2007, , Frankfurt

2 Web Application Developer bei der Nero AG / Karlsbad
Timo Holzherr Web Application Developer bei der Nero AG / Karlsbad Web-Community My Nero (PHP5, AJAX) Online Services für verschiedene Nero-Applikationen Lehrauftrag bei der Berufsakademie Stuttgart Vorlesung Software-Engineering 2 Betreuung von Studienarbeiten, Thema Compiler-Entwicklung

3 Agenda Was ist AutoSave? Praktische Anwendungen Formulareingaben überwachen Zeitintervalle steuern, Eingaben zählen AJAX-Request absenden Formular-Validierung

4 Was ist AutoSave? Auf AJAX basierendes Feature Für HTML-Formulare
Automatisches Speichern der Benutzer-Eingaben Eingaben überwachen Änderungen regelmäßig zum Server übertragen Recovery-Feature Browser-Absturz Versehentliches Schließen des Browserfensters

5 AutoSave – Praktische Anwendungen
Vor AJAX nur in Desktop-Applikationen Microsoft Office Heute bei vielen Online-Services My Nero ( Google Mail (

6 AutoSave bei My Nero

7 Regelmäßiges Speichern im Hintergrund
AutoSave bei My Nero Blog-Editor Regelmäßiges Speichern im Hintergrund

8 Recovery-Feature auf dem Login-Screen
AutoSave bei My Nero Recovery-Feature auf dem Login-Screen

9 Autosave bei Google Mail

10 AutoSave bei Google Mail
Während der Eingabe der Regelmäßiges Speichern der Eingaben

11 AutoSave bei Google Mail
Der Benutzer findet die automatisch gespeicherte im Ordner Entwürfe

12 Entwicklung eines AutoSave-Frameworks
Trennung der Aufgaben Formulareingaben überwachen Zeitintervalle steuern Formulardaten absenden Verschiedene Klassen FormObservable.js AutoSave.js Note.js Vorteil der Trennung Komponenten können einzeln verwendet werden Bsp.: Live-Validierung von Formularen durch FormObservable

13 Formulareingaben überwachen
Eingaben des Benutzers müssen überwacht werden Registrieren für Events aller Form-Elemente onkeyup (Nach einem Tastendruck) onmouseup (Nach einem Mausklick) onblur (Verlassen eines Formularfeldes) onchange (Ändern einer Check- oder Dropdown-Box) Beim Auftreten dieser Events Prüfen, ob sich die Formularwerte geändert haben Mithilfe des Observer-Patterns Änderungen signalisieren

14 Klasse FormObservable
Speichert die Liste der Observer Initialisiert die Klasse an einer Form-Node Sendet ein Event an alle Observer Fügt einen Observer hinzu

15 Klasse FormObservable
var observable = new FormObservable( document.forms[0] ); observable.addObserver( { onupdate: function() { alert(“Form element has been updated.“); } } );

16 Klasse FormObservable: Initialisierung
FormObservable = function( formNode ) { var events = [ 'keyup', 'mouseup', 'blur', 'change' ]; var call = this._onFieldChange.bind( this ); for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item( i ); for( var j=0; j < events.length; j++ ) { elem.addEventListener( events[j], call, true ); } Der Konstruktor erwartet ein HTML-Form-Objekt als Parameter

17 Klasse FormObservable: Initialisierung
FormObservable = function( formNode ) { var events = [ 'keyup', 'mouseup', 'blur', 'change' ]; var call = this._onFieldChange.bind( this ); for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item( i ); for( var j=0; j < events.length; j++ ) { elem.addEventListener( events[j], call, true ); } Events, die überwacht werden sollen

18 Klasse FormObservable: Initialisierung
FormObservable = function( formNode ) { var events = [ 'keyup', 'mouseup', 'blur', 'change' ]; var call = this._onFieldChange.bind( this ); for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item( i ); for( var j=0; j < events.length; j++ ) { elem.addEventListener( events[j], call, true ); } Methode, die später die Events verarbeitet

19 Klasse FormObservable: Initialisierung
FormObservable = function( formNode ) { var events = [ 'keyup', 'mouseup', 'blur', 'change' ]; var call = this._onFieldChange.bind( this ); for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item( i ); for( var j=0; j < events.length; j++ ) { elem.addEventListener( events[j], call, true ); } bind: Methode aus der Bibliothek Prototype [1] Setzt den Kontext der Methode auf die Instanz this JS-Event-Handling: Ansonsten Verlust des Kontextes

20 Klasse FormObservable: Initialisierung
FormObservable = function( formNode ) { var events = [ 'keyup', 'mouseup', 'blur', 'change' ]; var call = this._onFieldChange.bind( this ); for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item( i ); for( var j=0; j < events.length; j++ ) { elem.addEventListener( events[j], call, true ); } Jedem Formular-Element wird call als Event-Listener hinzugefügt

21 Klasse FormObservable: Initialisierung
FormObservable = function( formNode ) { var events = [ 'keyup', 'mouseup', 'blur', 'change' ]; var call = this._onFieldChange.bind( this ); for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item( i ); for( var j=0; j < events.length; j++ ) { elem.addEventListener( events[j], call, true ); } Hier: Event-Implementierung nur für Mozilla Firefox Empfohlen: Bibliothek für Browser-Abstraktion Bsp.: Prototype [1]

22 Klasse FormObservable: _onFieldChange
FormObservable.prototype._onFieldChange = function( ) { for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item(i); var oldVal = this._getStoredValue( elem ); var newVal = elem.value; if( newVal != oldVal ) { this.notifyObservers( 'update' ); this._setStoredValue( elem, newVal ); } Wird vom JS-Event-Handling aufgerufen, wenn eines der überwachten Ereignisse eintritt keyup mouseup blur change

23 Klasse FormObservable: _onFieldChange
FormObservable.prototype._onFieldChange = function( ) { for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item(i); var oldVal = this._getStoredValue( elem ); var newVal = elem.value; if( newVal != oldVal ) { this.notifyObservers( 'update' ); this._setStoredValue( elem, newVal ); } Dabei wird jedes Formularelement auf eine Änderung geprüft

24 Klasse FormObservable: _onFieldChange
FormObservable.prototype._onFieldChange = function( ) { for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item(i); var oldVal = this._getStoredValue( elem ); var newVal = elem.value; if( newVal != oldVal ) { this.notifyObservers( 'update' ); this._setStoredValue( elem, newVal ); } FormObservable: Merkt sich lokal für jedes Element den letzten Wert

25 Klasse FormObservable: _onFieldChange
FormObservable.prototype._onFieldChange = function( ) { for( var i=0; i < formNode.elements.length; i++ ) { var elem = formNode.elements.item(i); var oldVal = this._getStoredValue( elem ); var newVal = elem.value; if( newVal != oldVal ) { this.notifyObservers( 'update' ); this._setStoredValue( elem, newVal ); } Observers über eine Änderung informieren Wertänderung lokal merken

26 Klasse FormObservable: Default Values
Problem Formularelemente mit Default-Values Beim ersten Klick würde das System vermuten, dass sich Elemente mit Default-Values geändert haben Abhilfe Default-Values zu Beginn als Startwert merken

27 Klasse FormObservable: _loadDefaultValues
FormObservable = function( formNode ) { … // Initialisierung der Event-Handler this._loadDefaultValues(); } Nach der bereits erwähnten Initialisierung: Laden der Default Values

28 Klasse FormObservable: _loadDefaultValues
FormObservable = function( formNode ) { … // Initialisierung der Event-Handler this._loadDefaultValues(); } FormObservable.prototype._loadDefaultValues = function( ) { for( var i=0; i < this.form.elements.length; i++ ) { var elem = this.form.elements.item(i); this._setStoredValue( elem, elem.value ); } };

29 Beispiel Observable [2]
var observable = new FormObservable( document.forms[0] ); observable.addObserver( { onupdate: function() { alert(“Form element has been updated.“); } } ); Beispiel Observable [2]

30 Observer-Notifications empfangen
Empfangen der Observer-Notifications AJAX-Request muss an FormObservable gekoppelt werden Ansatz: var observable = new FormObservable( document.forms[0] ); observable.addObserver( { onupdate: function() { // AJAX Request senden } } );

31 Observer-Notifications empfangen
Problem Bei jedem Tastaturanschlag Übertragung der Änderung Viele HTTP-Requests Überlastung des Web-Servers Lösung Zeitverzögertes Senden der Daten Einstellbares Timeout

32 Klasse AutoSave Hält eine Instanz der Klasse FormObservable vor
Instanziert die Klasse an einer Form-Node, Timeout konfigurierbar Fügt einen Observer hinzu, delegiert FormObservable Setzt alle Timeouts zurück

33 Klasse AutoSave var as = new AutoSave( document.forms[0], 5 );
as.addObserver( { ontimeout: function(){ /* AJAX Request senden */ }, onupdate: function() { /* aktivieren */ } } );

34 Klasse AutoSave: Initialisierung
AutoSave = function( form, saveTime ) { this._options = { form: form, saveTime: saveTime * 1000, // convert into milliseconds }; this._interval = null; this._observable = new FormObservable( form ); this._observable.addObserver( { onupdate: this._updateInterval.bind( this ), ontimeout: this.reset.bind( this ) } ); Die übergebenen Parameter werden gespeichert

35 Klasse AutoSave: Initialisierung
AutoSave = function( form, saveTime ) { this._options = { form: form, saveTime: saveTime * 1000, // convert into milliseconds }; this._interval = null; this._observable = new FormObservable( form ); this._observable.addObserver( { onupdate: this._updateInterval.bind( this ), ontimeout: this.reset.bind( this ) } ); Klassenvariable _interval wird initialisiert. Referenziert Timeout, um es wieder zu stoppen var to = window.setTimeout( callback, zeit ); window.clearTimeout( to );

36 Klasse AutoSave: Initialisierung
AutoSave = function( form, saveTime ) { this._options = { form: form, saveTime: saveTime * 1000, // convert into milliseconds }; this._interval = null; this._observable = new FormObservable( form ); this._observable.addObserver( { onupdate: this._updateInterval.bind( this ), ontimeout: this.reset.bind( this ) } ); FormObservable instanzieren und Observer hinzufügen

37 Klasse AutoSave: _updateInterval
AutoSave.prototype._updateInterval = function( ) { this._resetInterval(); this._interval = window.setTimeout( this._timeExceeded.bind( this ), this._options.saveTime ); }; Wird bei einem Update-Event des FormObservable aufgerufen (Änderungen am Formular)

38 Klasse AutoSave: _updateInterval
AutoSave.prototype._updateInterval = function( ) { this._resetInterval(); this._interval = window.setTimeout( this._timeExceeded.bind( this ), this._options.saveTime ); }; AutoSave.prototype._resetInterval = function() { if( this._interval ) { window.clearTimeout( this._interval ); this._interval = null; }

39 Klasse AutoSave: _updateInterval
AutoSave.prototype._updateInterval = function( ) { this._resetInterval(); this._interval = window.setTimeout( this._timeExceeded.bind( this ), this._options.saveTime ); }; Timeout starten Aufgerufene Methode: AutoSave._timeExceeded() Setzt this._interval zurück Löst mit notifyObservers das Event „timeout“ aus

40 Beispiel AutoSave[2] var as = new AutoSave( document.forms[0] );
as.addObserver( { onupdate: function() { document.forms[0].draft.disabled = null; }, ontimeout: function() { alert(“Saving form data.“); document.forms[0].draft.disabled = 'disabled'; } } ); Beispiel AutoSave[2]

41 Durchgehendes Tippen Problem Ansatz
Regelmäßiges Eingeben in ein Textfeld Das Formular wird nie automatisch abgeschickt Ansatz Eingaben zählen (Maus, Tastatur) Ab gewisser Anzahl an Änderungen das Speichern erzwingen

42 Klasse AutoSave: HitsCounter

43 Klasse AutoSave mit HitsCounter
Neuer Parameter hitsLimit Spezifiziert die maximale Anzahl ungespeicherter Änderungen Observer-Events: update: Element hat sich geändert timeout: Timeout wurde erreicht hitslimit: Maximale Anz. an Änderungen erreicht

44 Konkrete Anwendung von AutoSave.js Verwendet AutoSave Observer-Events
Klasse Note Konkrete Anwendung von AutoSave.js Verwendet AutoSave Observer-Events update: aktivieren timeout: Daten senden, deaktivieren hitslimit: Daten senden, deaktivieren

45 Speicherung der Daten (1)
Implementierung des AJAX-Requests Abhängig vom eingesetzten AJAX-Framework Datenbank-Schema zum Ablegen der AutoSave-Daten Abhängig von der Anwendung Extra-Tabelle „autosaves“ Inmitten der Nutzdaten: flag: „draft“

46 Speicherung der Daten (2)
Fall: Speicherung der Daten inmitten der Nutzdaten 1. AutoSave-Request würde einen neuen Eintrag anlegen INSERT INTO … Folge-Requests müssen diesen Datensatz aktualisieren UPDATE … WHERE ID = … Deshalb AutoSave-Request muss den PK zurückgeben Notizen id INT(10) PRIMARY KEY title VARCHAR(50) body TEXT lang VARCHAR(5) draft TINYINT(1)

47 Speicherung der Daten (2)

48 Beim Empfangen von Formularen
Formularvalidierung Beim Empfangen von Formularen Formularvalidierung Sind alle Felder ausgefüllt Überschreiten die Felder nicht die Maximallänge Bei AutoSave-Requests Keine oder nur einfache Validierung! Sonst: Keine AutoSave der Eingaben obwohl evtl nur ein Feld fehlt

49 Demonstration Ergebnis
Framework für AutoSaving Kann universell eingesetzt werden AJAX-Requests und Persistence müssen selbst implementiert werden

50 [2] Folien und Beispiele dieses Vortrags
Verweise [1] Prototype JS-Bibliothek für einfache DOM-Manipulation und AJAX-Requests [2] Folien und Beispiele dieses Vortrags


Herunterladen ppt "AutoSave für AJAX-Formulare Timo Holzherr"

Ähnliche Präsentationen


Google-Anzeigen