6 Ajax und JSF
Ajax hat in den letzten Jahren enorm an Bedeutung gewonnen und ist aus der Webentwicklung nicht mehr wegzudenken. Mit der stark zunehmenden Nutzung des Internets in den letzten Jahren stieg auch der Wunsch nach einer interaktiveren und umfangreicheren Benutzung von Webseiten, wie sie im Bereich herkömmlicher Desktop-Applikationen bereits seit vielen Jahren üblich und Benutzern vertraut ist. Diese Lücke soll durch neue Ansätze in der Webtechnologie geschlossen werden. Das grundlegende Ziel muss lauten, das Web noch stärker an die oft sehr unterschiedlichen Bedürfnisse der Benutzer anzupassen.Geschichte des Web: In der Geschichte des World Wide Web bestand der erste technologische Ansatz (Web in der Version 1.0) darin, dem Benutzer rein statische HTML-Seiten zu präsentieren. Diese waren schwer wartbar, boten kein dynamisches Verhalten und wiesen für den Benutzer eine oft undurchsichtige Benutzerführung auf.
Die nächste Phase - in der sich das Internet heute noch teilweise befindet - wurde durch den Einsatz von dynamischen Inhalten eingeleitet. Der Benutzer bekommt nach Interaktion mit dem Server dynamische und für ihn spezifische Inhalte aufbereitet. Diesem Ansatz für das World Wide Web wird auch - seltener gebraucht - die Versionsnummer 1.5 zugeschrieben.
Web 2.0: Der Begriff des Web in der Version 2.0 ist eine logische Weiterentwicklung, die den Bedürfnissen der Benutzer folgt. Erstmals im Oktober 2004 für eine Konferenz gebraucht, steht er für vernetzte und personalisierte Plattformen, die Desktop-Applikationen in vielen Bereichen ersetzen sollen.
Web 2.0 ist ein Begriff, dessen Definition recht breit gefasst ist. Ajax ist eine jener Technologien, die die Realisierung von Anwendungen des Web in der Version 2.0 unterstützen sollen. Im Laufe der letzten Jahre erfreute sich Ajax einer immer größeren Beliebtheit, wobei nicht zuletzt auch Google mit seinen auf dieser Technologie aufsetzenden Applikationen zu einem rasanten Aufschwung in Verwendung und Bekanntheitsgrad beitrug.
Bevor wir uns in Abschnitt [Sektion: Ajax in JSF 2.0] auf die Details und erste praktische Beispiele stürzen, werden wir in Abschnitt [Sektion: Einführung in Ajax -- "`Asynchronous JavaScript And XML"'] den Begriff Ajax etwas genauer unter die Lupe nehmen. In den Abschnitten [Sektion: Ajax in Kompositkomponenten] und [Sektion: Eigene Ajax-Komponenten] ziehen wir dann alle Register und setzen Ajax mit Kompositkomponenten ein. Abschnitt [Sektion: MyGourmet 14: Ajax] zeigt anschließend die Integration von Ajax in MyGourmet . Zu guter Letzt präsentieren wir in Abschnitt [Sektion: Werkzeuge für den Ajax-Entwickler] noch einige Werkzeuge, die Ihnen bei der Arbeit an Ajax-Anwendungen unter die Arme greifen können.
6.1 Einführung in Ajax -- "`Asynchronous JavaScript And XML"'
Ajax ist an sich keine eigenständige Technologie im Bereich des Web, sondern vielmehr ein Sammelbegriff für eine Vielzahl von Technologien, die teilweise bereits seit mehreren Jahren eingesetzt werden. Der Name Definition von Ajax: wurde zum ersten Mal im Februar 2005 von Jesse James Garrett und der Agentur "Adaptive Path" in einem Essay über neue Entwicklungen und zukünftige Trends im Bereich von Webapplikationen erwähnt. http://adaptivepath.com/publications/essays/archives/000385.php: Ajax steht für " A synchronous J avaScript A nd X ML" und setzt auf Basistechnologien wie XHTML, Cascading Style Sheets (CSS), Document Object Model (DOM), XML, JavaScript und das XMLHttpRequest-Objekt auf.Der zentrale Baustein einer Ajax-Applikation ist die Skriptsprache JavaScript. Folglich muss JavaScript im Browser aktiviert sein, um die Ajax-Funktionalität nutzen zu können. Noch vor einigen Jahren ist JavaScript vor allem für grafische Spielereien und clientseitige Validierung benutzt worden - diese Reduzierung auf das Unwesentliche, gemeinsam mit den Problemen bei der Browserkompatibilität, haben der Sprache nicht den besten Ruf beschert. Mittlerweile ist JavaScript als Sprache gereift und eine wichtige Grundlage für Webframeworks wie JavaServer Faces und für hochinteraktive Webanwendungen geworden.
Üblicherweise greift jede mit Ajax entwickelte Webseite auf eine bereits vorhandene JavaScript-Bibliothek zurück, die als eine clientseitige Zwischenschicht zwischen der Webseite und dem Server eingezogen wird. Ein solches Framework bietet Code für die Erzeugung und die Behandlung des XMLHttpRequest-Objekts an. Darüber hinaus deckt es oft umfangreiche Funktionalität ab, die dem Webentwickler das Leben vereinfacht und von der Komplexität der Ajax-Benutzung abstrahiert. JavaScript Bibliotheken: Eine solche Bibliothek behandelt auch die Unterschiede zwischen den einzelnen Browsern und verschont den Entwickler von dem großen Testaufwand, den eine Implementierung über die Browser hinweg mit sich bringt.
Bei der Verwendung von Ajax in einer Webapplikation gibt es Unterschiede hinsichtlich der Intensität des Einsatzes. Die einfachste Möglichkeit ist eine kleine Ajax-Interaktion mit einer Verwendung neben den herkömmlichen dynamischen und statischen Abläufen. Der Gebrauch mehrerer Ajax-basierter Komponenten ist schon eine Stufe darüber anzusiedeln. Schließlich ist die Realisierung einer Applikation vollständig in Ajax möglich; sämtliche Abläufe erfolgen dann über im Client ausgeführtes JavaScript. Beim Start einer solchen Anwendung wird ein kompletter Client in den Speicher geladen, bestehend aus Geschäfts- und Präsentationslogik sowie aus den zu benutzenden Daten. Die Logik wird mittels JavaScript implementiert - für den Bau solcher Anwendungen sollten Sie also in der Verwendung von JavaScript sehr firm sein, oder den Einsatz des GWT-Frameworks in Erwägung ziehen. Wir werden uns nur mit den ersten beiden Ansätzen beschäftigen.
Der zum Markennamen avancierte Begriff Ajax enthält im Wortlaut eigentlich
nur eine für Ajax wirklich zwingend notwendige Technologie, nämlich JavaScript. Die
asynchrone Interaktion ist nicht unbedingt notwendig - bei einem
asynchronen Interaktionsablauf, wie er standardmäßig bei Ajax erfolgt, wird während
der HTTP-Anfrage/Antwort-Phase die clientseitige Abarbeitung von JavaScript
fortgesetzt, um etwa Validierungen oder auch visuelle Ausgaben und Rückmeldungen
durchzuführen. Browserseitig findet also keine Blockierung statt, wie das bei einem
synchronen Ablauf der Fall wäre. Es ist aber möglich, Ajax-Anfragen synchron zu
fahren, auch wenn davon abzuraten ist. Genauso ist auch ein XML-konformes Format in
der HTTP-Antwort nicht zwingend, es kann auch HTML-Code oder jedes andere denkbare
Format (häufig JSON) zurückgegeben werden.
Wie sieht nun eine typische Ajax-Webanwendung aus? Im Verhalten ähnelt sie einer
herkömmlichen Desktop-Anwendung, bei der wir viel weiter gehende Funktionalität
bereits seit Jahren gewohnt sind, die aber so bisher im Web einfach nicht
realisierbar war. Die Interaktion zwischen dem Benutzer bzw. Browser und Webserver
läuft demnach wesentlich flüssiger ab.Möglich ist dies durch die Technik, Daten asynchron vom Server zu laden, während clientseitig das System nicht zum Stillstand kommen muss. Außerdem wird die Oberfläche des Browsers nur mit der angeforderten Information aktualisiert, also nicht komplett neu geladen.
6.2 Ajax in JSF 2.0
Die rasante Entwicklung von Ajax ist natürlich auch an der JSF-Welt nicht spurlos vorübergegangen. Dass JSF und Ajax sich gut vertragen, beweisen eine ganze Reihe von Komponentenbibliotheken und Ajax-Frameworks speziell für JSF. Jede dieser Lösungen funktioniert für sich genommen einwandfrei. Das Problem liegt - wie bei vielen Entwicklungen der letzten Jahre im JSF-Umfeld - an der fehlenden Spezifikation und der daraus entstandenen Inkompatibilität der unterschiedlichen Produkte. Obwohl alle Lösungen das gleiche Ziel - die Integration von JSF und Ajax - verfolgen, unterscheidet sich die technische Umsetzung doch teils erheblich. Mit JSF 2.0 ist dieses Problem Geschichte, da die Spezifikation eine Standardisierung der Ajax-Unterstützung beinhaltet.JSF 2.0 definiert eine JavaScript-Bibliothek, die grundlegende Ajax-Operationen wie das Senden einer Anfrage und das Bearbeiten der Antwort abdeckt. Mit dieser standardisierten Schnittstelle ist gewährleistet, dass alle Komponenten clientseitig dieselbe Funktionalität einsetzen und sich nicht in die Quere kommen.
Diese JavaScript-API bildet auch die Grundlage für die Integration von Ajax in JSF-Anwendungen. JSF bietet grundsätzlich zwei verschiedene Ansätze, um Ansichten mit Ajax-Funktionalität auszustatten. Zum einen können Entwickler zum Absetzen einer Ajax-Anfrage direkt die Funktion der JavaScript-API aufrufen. Zum anderen gibt es mit dem Tag f:ajax eine deklarative Variante, um eine Komponente oder sogar einen ganzen Bereich einer Seitendeklaration mit Ajax-Funktionalität auszustatten.
Die Spezifikation kümmert sich allerdings nicht nur um die Clientseite. Auch die Bearbeitung einer Ajax-Anfrage am Server ist umfassend spezifiziert. JSF 2.0 erweitert den Lebenszyklus so, dass zum Bearbeiten einer Ajax-Anfrage nur die relevanten Teile des Komponentenbaums ausgeführt ( Partial-View-Processing ) und gerendert ( Partial-View-Rendering ) werden.
Im Laufe dieses Abschnitts gehen wir auf die Details der Ajax-Integration in JSF 2.0 ein. Nach einem ersten Beispiel mit f:ajax in Abschnitt [Sektion: Ein erstes Beispiel mit f:ajax] folgen in Abschnitt [Sektion: f:ajax im Einsatz] noch weitere Beispiele. Abschnitt [Sektion: JavaScript-API] widmet sich anschließend der JavaScript-API für Ajax und Abschnitt [Sektion: Partieller JSF-Lebenszyklus] gibt Einblicke in den partiellen Lebenszyklus.
6.2.1 Ein erstes Beispiel mit f:ajax
Als erstes Beispiel werden wir das Ein- und Ausblenden der Kreditkartendaten in der Ansicht editCustomer.xhtml auf Ajax umstellen. Bis jetzt löste ein Klick auf das Auswahlfeld "Kreditkarte angeben" über JavaScript ein Übermitteln der Form aus. Am Server fand dadurch natürlich ein Durchlauf des Lebenszyklus über den kompletten Komponentenbaum statt. Eigentlich wollen wir aber nur die Eigenschaft useCreditCard neu setzen und die zwei Labels und Eingabekomponenten der Kreditkartendaten abhängig davon ein- oder ausblenden.Wir wollen erreichen, dass ein Klick auf das Auswahlfeld eine Ajax-Anfrage an den Server auslöst. Als Reaktion auf die Anfrage soll der registrierte Value-Change-Listener ausgeführt und der Bereich mit den Kreditkartendaten neu gerendert werden. JSF 2.0 erleichtert uns diese Aufgabe enorm. Mit dem Tag f:ajax kann eine Komponente mit Ajax-Funktionalität ausgestattet werden, indem es als Kind-Tag des mit Ajax-Unterstützung zu versehenden Elements in die Deklaration eingefügt wird. In unserem Beispiel ergibt sich die gewünschte Funktionalität durch das Hinzufügen des f:ajax -Elements zur Auswahlkomponente h:selectBooleanCheckbox . Listing Einsatz von f:ajax zum Umschalten der Kreditkartendaten zeigt die relevanten Teile der Deklaration editCustomer.xhtml . Aus Gründen der einfacheren Handhabung haben wir die Form in zwei Bereiche geteilt: einen für die Basisdaten und einen für die Kreditkartendaten.
<h:form id="form">
<h:panelGrid id="baseData" columns="2">
...
<h:selectBooleanCheckbox id="useCreditCard"
value="#{customerBean.customer.useCreditCard}"
valueChangeListener="#{customerBean.useCreditCardChanged}">
<f:ajax render="ccData"/>
</h:selectBooleanCheckbox>
</h:panelGrid>
<h:panelGrid id="ccData" columns="2">
...
</h:panelGrid>
...
</h:form>
Die kleine Änderung hat einen durchschlagenden Effekt. Wie verarbeitet JSF das Tag f:ajax ? Der gewählte Ansatz ist so einfach wie mächtig. JSF setzt das Tag f:ajax beim Rendern unserer Auswahlkomponente als Aufruf der Funktion jsf.ajax.request() im Attribut onchange um. Mit dem Attribut render teilen wir JSF mit, welche Komponente neu gerendert werden soll. In unserem Fall ist das die Panel-Grid-Komponente mit der ID ccData .
Beachten Sie bitte auch, dass die h:selectBooleanCheckbox -Komponente nicht mehr immediate ist. Zuvor war das notwendig, da bei einem Klick auf das Auswahlfeld immer die komplette Form im Lebenszyklus ausgeführt wurde und einige der anderen Formularfelder verpflichtend anzugeben sind, und damit unschöne Validierungsmeldungen eingeblendet wurden. Mit Ajax wird der Lebenszyklus nur mehr partiell für die eine Komponente ausgeführt, es erscheinen keine Validierungsmeldungen für andere Komponenten.
Schreiben wir das f:ajax -Tag in Listing Einsatz von f:ajax zum Umschalten der Kreditkartendaten mit den Standardwerten für seine Attribute an, so erhalten wir:
<f:ajax event="valueChange" execute="@this"
render="ccData"/>
Das Ergebnis der Langschreibweise ist identisch. Der Wert des Attributs event bestimmt das Ereignis, von dem
die Ajax-Anfrage ausgelöst wird. Mögliche Werte dafür sind valueChange für Eingabekomponenten, action für Steuerkomponenten und alle anderen
HTML-Ereignisse - allerdings ohne das Präfix on . Wir könnten also mit
dem Wert click die Ajax-Anfrage genauso gut durch eine Klick auf das
Auswahlfeld auslösen. Das Attribut execute definiert, welche Komponenten
beim Abarbeiten des Lebenszyklus am Server bearbeitet werden. Die Konstante
@this bezeichnet dabei die umschließende Komponente. Die Attribute
event und execute können in unserem Fall weggelassen werden, da
es sich bei den Werten valueChange und @this um die Defaultwerte
für Eingabekomponenten handelt. Was JSF am Server als Reaktion auf diese Anfrage
macht, zeigen wir Ihnen in Abschnitt [Sektion: Partieller JSF-Lebenszyklus] .Listing Umschalten der Kreditkartendaten mittels JavaScript-API zeigt die zweite Variante, eine Komponente mit Ajax auszustatten. Nachdem das Absenden einer Ajax-Anfrage immer über die standardisierte JavaScript-API läuft, kann die dafür zuständige Funktion jsf.ajax.request() auch direkt verwendet werden. Die Funktion übernimmt als Parameter das auslösende DOM-Element, das Ereignis und ein assoziatives Array mit Optionen. Mehr dazu in Abschnitt [Sektion: JavaScript-API] .
<h:selectBooleanCheckbox id="useCreditCard"
value="#{customerBean.customer.useCreditCard}"
valueChangeListener=
"#{customerBean.useCreditCardChanged}"
onchange="jsf.ajax.request(
this, event, {render: 'form:ccData'});"/>
6.2.2 f:ajax im Einsatz
Mit dem Tag f:ajax können alle Standardkomponenten in JSF 2.0 mit Ajax-Verhalten ausgestattet werden. Genauer gesagt sind es alle Komponenten, die das Interface ClientBehaviorHolder implementieren, wodurch es relativ einfach möglich ist, auch eigene Komponenten oder solche aus Komponentenbibliotheken für f:ajax fit zu machen. Damit steht der Kompatibilität von Komponenten aus unterschiedlichen Quellen in Bezug auf Ajax nichts mehr im Wege.f:ajax kann auf zwei Arten zum Einsatz kommen. Zum einen kann eine einzelne Komponente mit Ajax-Verhalten ausgerüstet werden, indem f:ajax als Kind-Tag eingefügt wird. Zum anderen ist es auch möglich, mit f:ajax einen ganzen Bereich einer Deklaration auf Ajax umzustellen.
Hier die wichtigsten Attribute des Tags f:ajax :
- event:
Name des Ereignisses, das die Ajax-Anfrage auslöst. Mögliche Werte sind valueChange für Eingabekomponenten, action für Steuerkomponenten und alle anderen HTML-Ereignisse - allerdings ohne das Präfix on . Der Defaultwert dieses Attributs wird von der Komponente bestimmt. - execute:
Eine durch Leerzeichen separierte Liste der IDs jener Komponenten, die beim Bearbeiten der Ajax-Anfrage durch JSF im Lebenszyklus ausgeführt werden sollen. Kann auch die Konstanten @this (das Element selbst), @form (das Formular des Elements), @all (alle Elemente) und @none (kein Element) beinhalten. Wenn das Attribut als Value-Expressions gesetzt wird, muss der Typ der Eigenschaft List<String> sein. Der Defaultwert ist @this . - render:
Eine durch Leerzeichen separierte Liste der IDs jener Komponenten, die beim Bearbeiten der Ajax-Anfrage durch JSF im Lebenszyklus gerendert werden sollen. Kann auch die Konstanten @this , @form , @all und @none beinhalten. Wenn das Attribut als Value-Expressions gesetzt wird, muss der Typ der Eigenschaft List<String> sein. Der Defaultwert ist @none . - onevent:
Erlaubt das Registrieren einer JavaScript-Callback-Funktion für Ajax-Ereignisse. Details folgen in Abschnitt [Sektion: JavaScript-API] . - onerror:
Erlaubt das Registrieren einer JavaScript-Callback-Funktion für Fehler, die beim Bearbeiten der Ajax-Anfrage auftreten. Details folgen in Abschnitt [Sektion: JavaScript-API] . - disabled:
Das Ajax-Verhalten wird "abgeschaltet", wenn dieses Attribut auf true gesetzt ist.
Listing f:ajax im Einsatz: Beispiel 1 zeigt das Beispiel bereits in einer mit Ajax erweiterten Variante. Das Tag f:ajax bewirkt, dass die Schaltfläche über Ajax das Ausführen der beiden Eingabekomponenten und das Rendern des Textfelds anstößt. Wenn Sie im Browser einen Vor- und Nachnamen eingeben und die Schaltfläche aktivieren, wird das Textfeld ohne Neuaufbau der Ansicht aktualisiert.
<h:form id="form">
<h:panelGrid columns="1">
<h:inputText id="first" value="#{test.first}"/>
<h:inputText id="last" value="#{test.last}"/>
<h:commandButton value="Show">
<f:ajax execute="first last" render="name"/>
</h:commandButton>
</h:panelGrid>
<h:outputText id="name" value="#{test.name}"/>
</h:form>
Im zweiten Beispiel kommt ein zusätzliches f:ajax -Tag zum Einsatz, um einen ganzen Bereich der Deklaration mit Ajax-Verhalten auszustatten. Listing f:ajax im Einsatz: Beispiel 2 zeigt die erweiterte Deklaration.
<h:form id="form">
<f:ajax render="name">
<h:panelGrid columns="1">
<h:inputText id="first" value="#{test.first}"/>
<h:inputText id="last" value="#{test.last}"/>
<h:commandButton value="Show">
<f:ajax execute="first last" render="name"/>
</h:commandButton>
</h:panelGrid>
</f:ajax>
<h:outputText id="name" value="#{test.name}"/>
</h:form>
Tabelle tab:ajax-default-events zeigt eine Übersicht aller Standardkomponenten mit Defaultereignissen.
| Komponente | Defaultereignis |
| h:commandButton | action |
| h:commandLink | action |
| h:inputText | valueChange |
| h:inputTextarea | valueChange |
| h:inputSecret | valueChange |
| h:selectBooleanCheckbox | valueChange |
| h:selectOneRadio | valueChange |
| h:selectOneListbox | valueChange |
| h:selectOneMenu | valueChange |
| h:selectManyCheckbox | valueChange |
| h:selectManyListbox | valueChange |
| h:selectManyMenu | valueChange |
<h:form id="form">
<f:ajax event="dblclick" render="name">
<h:panelGrid columns="1">
<h:inputText id="first" value="#{test.first}"/>
<h:inputText id="last" value="#{test.last}"/>
<h:commandButton value="Show">
<f:ajax execute="first last" render="name"/>
</h:commandButton>
</h:panelGrid>
</f:ajax>
<h:outputText id="name" value="#{test.name}"/>
</h:form>
Das nächste Beispiel in Listing f:ajax im Einsatz: Beispiel 4 ist wiederum nur eine Variante des bereits bekannten Formulars. Diesmal gibt es jedoch zwei Textfelder zur Ausgabe des Namens: Das erste liegt innerhalb der Form und hat die ID inner . Das zweite Textfeld liegt außerhalb und hört auf die ID outer . Das äußere Feld soll immer dann aktualisiert werden, wenn sich der Wert eines der Eingabefelder ändert, wohingegen das innere durch einen Klick auf die Schaltfläche aktualisiert werden soll. Das sollte an und für sich kein Problem darstellen. Wenn das Attribut render des inneren f:ajax -Tags auf inner und das des äußeren auf outer gesetzt wird, sollte sich doch genau dieses Verhalten einstellen. Tut es aber nicht - JSF beschwert sich schon beim Laden der Seite, dass die ID outer nicht existiert. Warum das so ist, klären wir gleich.
<h:form id="form">
<f:ajax render=":outer">
<h:panelGrid columns="1">
<h:inputText id="first" value="#{test.first}"/>
<h:inputText id="last" value="#{test.last}"/>
<h:commandButton value="Show">
<f:ajax execute="first last" render="inner"/>
</h:commandButton>
</h:panelGrid>
</f:ajax>
<h:outputText id="inner" value="#{test.name}"/>
</h:form>
<h:outputText id="outer" value="#{test.name}"/>
Im letzten Beispiel in Listing f:ajax im Einsatz: Beispiel 5 zeigen wir Ihnen noch, wie Sie mit einfachen Mitteln zwei h:selectOneMenu -Komponenten miteinander verknüpfen. Die Auswahlmöglichkeiten der zweiten Komponente sollen von der getätigten Auswahl in der ersten Komponente abhängen und über Ajax aktualisiert werden. Ein gutes Beispiel dafür ist die Auswahl eines Landes und eines dazu passenden Bundeslandes. Mit dem f:ajax -Tag verpassen wir der ersten Komponente das dazu nötige Ajax-Verhalten. Immer wenn ein Benutzer den Wert im Browser ändert, wird eine Ajax-Anfrage abgesetzt und die zweite Komponente neu gerendert. Die Eigenschaft test.stateItems muss dazu lediglich die Liste der Bundesländer abhängig vom gewählten Land zurückliefern. Der registrierte Value-Change-Listener ist für die Ajax-Funktionalität nicht notwendig, erleichtert uns aber die Arbeit, da wir damit das zuvor ausgewählte Bundesland löschen können, bevor die neue Liste angezeigt wird.
<h:form id="form">
<h:selectOneMenu id="country"
value="#{test.country}"
valueChangeListener="#{test.changeCountry}">
<f:selectItems value="#{test.countryItems}"/>
<f:ajax render="state"/>
</h:selectOneMenu>
<h:selectOneMenu id="state" value="#{test.state}">
<f:selectItems value="#{test.stateItems}"/>
</h:selectOneMenu>
</h:form>
6.2.3 JavaScript-API
JSF 2.0 definiert eine JavaScript-Bibliothek als clientseitige Grundlage für die Integration von Ajax. Die Bibliothek ist in der Ressource mit dem Namen jsf.js in der Bibliothek javax.faces abgelegt. Wenn Sie Ajax deklarativ mit dem Tag f:ajax einsetzen, müssen Sie sich um das Einbinden dieser Ressource keine Gedanken machen. Nur bei einem direkten Einsatz der JavaScript-API müssen Sie sich wie folgt darum kümmern:<h:outputScript name="jsf.js" library="javax.faces"
target="head"/>
Um die Skript-Ressource jsf.js selbst müssen Sie sich keine Gedanken machen.
Sie gehört zum Standardlieferumfang von JSF und ist in den Jar-Dateien inkludiert.
Auch beim Einsatz der JavaScript-API ist es wichtig, h:head und
h:body in der Seitendeklaration zu verwenden. Nur so kann garantiert werden,
dass das Skript richtig in der gerenderten Ausgabe am Browser ankommt.Hier eine Auflistung der wichtigsten Funktionen der JavaScript-API:
- jsf.ajax.request(source, event, options):
Diese Methode sendet eine Ajax-Anfrage an den Server. - jsf.ajax.response(request, context):
Diese Methode bearbeitet die Anwort des Servers auf die Ajax-Anfrage und ist für Endanwender nicht relevant. - jsf.ajax.addOnError(callback):
Diese Methode registriert eine Callback-Funktion zum Behandeln von Fehlern, die während der Bearbeitung der Ajax-Anfrage aufgetreten sind. - jsf.ajax.addOnEvent(callback):
Diese Methode registriert eine Callback-Funktion zum Behandeln von Ajax-Ereignissen.
6.2.3.1 Senden von Ajax-Anfragen
Die Methode jsf.ajax.request(source, event, options) ist das Herzstück der JavaScript-API von JSF. Sie allein ist für das Senden der asynchronen Ajax-Anfragen an den Server zuständig. Das Tag f:ajax ist nur eine einfachere Variante, um das Ajax-Verhalten auf deklarativem Weg in die Ansicht zu bringen. Beim Rendern macht JSF daraus wieder einen Aufruf der Funktion jsf.ajax.request() .Mit den Parametern source und event werden das DOM-Element und das DOM-Ereignis übergeben, die für das Auslösen der Ajax-Anfrage verantwortlich sind. Der dritte Parameter options ist ein assoziatives Array, mit dem weitere Optionen als Schlüssel-Wert-Paare an die Funktion übergeben werden. Diese Optionen entsprechen weitestgehend den bereits bekannten Attributen aus f:ajax . Über execute werden IDs auszuführender Komponenten angegeben und über render IDs von Komponenten, die neu zu zeichnen sind. Genügt beim Einsatz von f:ajax in den meisten Fällen eine relative ID, muss beim Aufruf der JavaScript-Funktion immer die komplette Client-ID angegeben werden. Die Funktion operiert ja direkt auf DOM-Ebene und kann keine relativen IDs über den Komponentenbaum von JSF auflösen.
Die Funktion jsf.ajax.request() baut die Ajax-Anfrage zusammen und schickt sie asynchron an den Server. Was JSF dort genau mit dieser Anfrage macht, verraten wir Ihnen in Abschnitt [Sektion: Partieller JSF-Lebenszyklus] . Sobald die Antwort auf die Anfrage vom Server zurückkommt, wird im Erfolgsfall die Funktion jsf.ajax.response() aufgerufen, um die Antwort zu verarbeiten und gegebenfalls Teile der Ansicht neu aufzubauen.
Listing Beispiel 5 mit Ajax über JavaScript zeigt noch einmal das Beispiel mit den beiden Auswahllisten aus dem letzten Abschnitt. Diesmal ist das Ajax-Verhalten allerdings direkt über die JavaScript-API realisiert. Genau wie vorher löst das Ändern des Werts in der ersten Komponente eine Ajax-Anfrage aus, die ein Neuzeichnen der zweiten Komponente veranlasst.
<h:form id="form">
<h:selectOneMenu id="country" value="#{test.country}"
valueChangeListener="#{test.changeCountry}"
onchange="jsf.ajax.request(
this, event, {render: 'form:state'})">
<f:selectItems value="#{test.countryItems}"/>
</h:selectOneMenu>
<h:selectOneMenu id="state" value="#{test.state}">
<f:selectItems value="#{test.stateItems}"/>
</h:selectOneMenu>
</h:form>
6.2.3.2 Status und Fehler von Ajax-Anfragen behandeln
Mit der Funktion jsf.ajax.addOnEvent(callback) kann eine Callback-Funktion zum Behandeln des Status von Ajax-Anfragen registriert werden. Die Callback-Funktion bekommt ein Objekt mit genaueren Angaben zum Ereignis übergeben, wobei vor allem die Eigenschaft status interessant ist. Sie nimmt die Werte begin für das Ereignis, kurz bevor die Anfrage an den Server geschickt wird, complete für das Ereignis, nachdem die Antwort vom Server zurückkommt, und success für das Ereignis nach erfolgreichem Abschluss der Anfrage an. Die Callback-Funktion wird also dreimal für jede Ajax-Anfrage aufgerufen. Listing Callback-Funktion für Ajax-Ereignisse zeigt eine Funktion, die für jedes Ereignis eine Meldung ausgibt. In Abschnitt [Sektion: Die Kompositkomponente ajaxStatus] zeigen wir Ihnen, wie Sie mit einfachsten Mitteln eine Kompositkomponente zum Darstellen einer Ajax-Status-Meldung erstellen.var processEvent = function processEvent(data) {
if (data.status == "begin") {
alert('Begin');
} else if (data.status == "complete") {
alert('Complete');
} else if (data.status == "success") {
alert('Success');
}
}
jsf.ajax.addOnEvent(processEvent);
Mit der Funktion jsf.ajax.addOnError(callback) kann eine Callback-Funktion registriert werden, die beim Auftreten eines Fehlers während der Bearbeitung einer Ajax-Anfrage aufgerufen wird. Die Callback-Funktion wird auch hier mit einem Objekt mit Detailinformationen versehen. Die Eigenschaft status kann die Werte httpError , serverError , malformedXML oder emptyResponse annehmen.
Eine über jsf.ajax.addOnError() registrierte Funktion wird im Fehlerfall bei jeder Ajax-Anfrage aufgerufen. addOnError() kann auch ohne Probleme mehrfach hintereinander aufgerufen werden, um mehr als eine Funktion zu registrieren. Wenn Sie eine Callback-Funktion für eine bestimmte Ajax-Anfrage benötigen, können Sie diese mit dem Attribut onerror von f:ajax oder beim Aufruf von jsf.ajax.request() als Option mit dem Schlüssel onerror registrieren.
6.2.4 Partieller JSF-Lebenszyklus
Eines der entscheidenden Features einer vernünftigen Ajax-Integration ist das partielle Ausführen ( Partial-View-Processing ) und Rendern ( Partial-View-Rendering ) des Komponentenbaums. Als Reaktion auf eine Ajax-Anfrage soll ja im ersten Schritt der Lebenszyklus nicht für den kompletten Komponentenbaum, sondern nur für die in der Anfrage spezifizierten Komponenten ausgeführt werden. Im zweiten Schritt wird als Ergebnis der Anfrage ein weiterer Teil des Komponentenbaums, der nicht mit dem ersten Teil übereinstimmen muss, gerendert.JSF 2.0 unterstützt das partielle Ausführen und Rendern direkt mit dem Standardlebenszyklus. Dazu ist der Lebenszyklus, wie in Abbildung Lebenszyklus mit Ajax zu erkennen, in die zwei logischen Bereiche Ausführen und Rendern aufgeteilt.
Welche Komponenten in den beiden Bereichen zum Einsatz kommen, wird über Parameter der Ajax-Anfrage bestimmt. Deren Werte entsprechen den Werten der f:ajax -Attribute execute und render beziehungsweise den gleichnamigen Parametern im assoziativen Array der Funktion jsf.ajax.request() .
Tabelle tab:ajax-request-params zeigt die wichtigsten Parameter der Ajax-Anfrage aus dem Einführungsbeispiel in Abschnitt [Sektion: Ein erstes Beispiel mit f:ajax] . JSF weiß anhand des Parameters javax.faces.partial.ajax , dass es sich um eine Ajax-Anfrage handelt und dass der Lebenszyklus partiell ausgeführt werden muss. Der Parameter javax.faces.source gibt an, welche Komponente die Anfrage ausgelöst hat, und die beiden restlichen Parameter bestimmen, welche Komponenten ausgeführt und gerendert werden.
| Parameter | Wert |
| javax.faces.partial.ajax | true |
| javax.faces.source | form:useCreditCard |
| javax.faces.partial.execute | form:useCreditCard |
| javax.faces.partial.render | form:grid |
6.3 Ajax in Kompositkomponenten
Im nächsten Beispiel werden wir die in Abschnitt Sektion: Die Komponente mc:collapsiblePanel erstellte Kompositkomponente collapsiblePanel auf Ajax umstellen. In der aktuellen Variante wird bei jedem Klick auf das Icon zum Ein- und Ausklappen des Inhalts die komplette Seite neu aufgebaut - ein nicht mehr zeitgemäßes Verhalten. Vielmehr soll bei einem Klick auf das Icon nur der Inhalt des Panels angezeigt oder ausgeblendet werden.Nichts leichter als das. Wie schon im letzten Beispiel lässt sich die Ajax-Unterstützung mit einer einzigen Zeile realisieren. Nachdem wir das von der Komponente h:commandButton ausgelöste Übermitteln der Seite auf Ajax umstellen wollen, fügen wir dort das Tag f:ajax hinzu. Listing Ajax in der Kompositkomponente collapsiblePanel zeigt den Implementierungsteil der Kompositkomponente mit Ajax-Unterstützung.
<cc:implementation>
<h:panelGroup layout="block"
styleClass="collapsiblePanel-header">
<h:commandButton id="toggle"
actionListener="#{cc.toggle}"
styleClass="collapsiblePanel-img"
image="#{resource[cc.collapsed ?
'mygourmet:toggle-plus.png' :
'mygourmet:toggle-minus.png']}">
<f:ajax render="@this panel-content"/>
</h:commandButton>
<cc:renderFacet name="header"/>
</h:panelGroup>
<h:panelGroup id="panel-content" layout="block">
<h:panelGroup rendered="#{!cc.collapsed}">
<cc:insertChildren/>
</h:panelGroup>
</h:panelGroup>
</cc:implementation>
Wie Sie vielleicht schon bemerkt haben, ist im Vergleich zur Nicht-Ajax-Version das Tag cc:insertChildren von zwei h:panelGroup -Tags umschlossen. Es handelt sich dabei nicht um einen Fehler, sondern um eine notwendige Maßnahme, damit Ajax richtig funktioniert. Die Erklärung ist einleuchtend: Da als Antwort auf die Ajax-Anfrage die Panel-Group mit dem Bezeichner panel-content neu gerendert und im Browser ersetzt wird, muss sie dort immer existieren. Mit nur einer Panel-Group würde die gerenderte Ausgabe nach dem ersten Einklappen aus dem DOM verschwinden und könnte nicht mehr eingeblendet werden.
Das f:ajax -Tag in Listing Ajax in der Kompositkomponente collapsiblePanel ist eine abgekürzte Form des folgenden Tags:
<f:ajax event="action" execute="@this"
render="@this panel-content"/>
Wie schon im letzten Beispiel können die Attribute event und
execute auch hier zugunsten der Standardwerte entfallen. Steuerkomponenten
definieren action als Defaultereignis für f:ajax , falls kein
anderer Wert angegeben wird.Doch damit noch nicht genug. Wir gehen noch einen Schritt weiter und stellen auch einen Teil des in die Kompositkomponente eingefügten Inhalts auf Ajax um. In der Ansicht showCustomer.xhtml befindet sich die Liste der Adressen eines Kunden in einer Kompositkomponente vom Typ dataTable (siehe Abschnitt Sektion: Die Komponente mc:dataTable ). Die Tabelle ist ihrerseits in eine collapsiblePanel -Komponente eingebettet. In der Tabelle gibt es für jede Adresse eine h:commandLink -Komponente zum Löschen der Adresse. Ein Klick auf diesen Link soll eine Ajax-Anfrage auslösen und das Neuzeichnen der Tabelle veranlassen.
Listing Ajax-Kompositkomponente collapsiblePanelim Einsatz zeigt die relevanten Teile der Seitendeklaration showCustomer.xhtml mit dem auf Ajax umgestellten Link.
<mc:collapsiblePanel id="addressPanel"
collapsed="#{customerBean.collapsed}">
<f:facet name="header">
<h3>#{msgs.title_addresses}</h3>
</f:facet>
<mc:dataTable id="addresses" var="address"
value="#{customerBean.customer.addresses}">
...
<h:column>
<h:commandLink action="#{addressBean.edit(address)}"
value="#{msgs.edit}"/>
<h:commandLink value="#{msgs.delete}"
action="#{customerBean.deleteAddress(address)}">
<f:ajax render=":form:addressPanel:addresses"/>
</h:commandLink>
</h:column>
</mc:dataTable>
</mc:collapsiblePanel>
Dieses Beispiel zeigt sehr schön, wie gut die einzelnen Neuerungen in JSF 2.0 miteinander harmonieren. Die Integration von Ajax in Kompositkomponenten stellt eine einfache Möglichkeit dar, Komponenten mit nach außen transparenter Ajax-Unterstützung zu erstellen.
6.4 Eigene Ajax-Komponenten
In diesem Abschnitt zeigen wir Ihnen anhand von zwei Kompositkomponenten, wie einfach, aber zugleich mächtig die Ajax-Integration von JSF ist. Die beiden Komponenten ajaxStatus und ajaxPoll nutzen direkt die JavaScript-API, um fortgeschrittene Ajax-Funktionalität anzubieten.6.4.1 Die Kompositkomponente ajaxStatus
Durch den vermehrten Einsatz von Ajax reduziert sich die Anzahl der Anfragen, die ein komplettes Neuladen der Ansicht nach sich ziehen. Neben den vielen Vorteilen, die Ajax mit sich bringt, gibt es auch einen kleinen Nachteil. Der Browser zeigt keinerlei Statusmeldung an, während eine Ajax-Anfrage bearbeitet wird. Bei jedem kompletten Seitenaufbau sieht der Benutzer einen Fortschrittsbalken oder eine Meldung, die Auskunft über den Status des Seitenaufbaus geben - nicht so bei Ajax-Anfragen. Und obwohl Ajax die Zeit zwischen Anfrage und Antwort erheblich verkürzt, kann es doch zu unklaren Situationen für den Benutzer kommen. Aus diesem Grund erstellen wir eine Komponente, die eine Statusmeldung anzeigt, solange eine Ajax-Anfrage aktiv ist.Mit den Informationen über die JavaScript-API aus Abschnitt [Sektion: JavaScript-API] ist es ein Leichtes, eine solche Komponente zu erstellen. Wir benötigen im Grunde nichts weiter als eine Statusmeldung und eine JavaScript-Funktion, die mit jsf.ajax.addOnEvent() als Callback registriert wird und die Statusmeldung dynamisch ein- und ausblendet. Das packen wir dann gemeinsam in eine Kompositkomponente und fertig ist die Ajax-Status-Komponente. Listing Kompositkomponente ajaxStatus zeigt die Deklaration.
<cc:interface>
<cc:attribute name="text" default="Loading"/>
<cc:attribute name="style"/>
<cc:attribute name="styleClass"
default="ajax-progress"/>
</cc:interface>
<cc:implementation>
<h:outputStylesheet library="mygourmet"
name="components.css"/>
<h:outputScript name="jsf.js" library="javax.faces"
target="head"/>
<h:outputScript name="ajaxStatus.js"
library="mygourmet" target="head"/>
<script type="text/javascript">
registerAjaxStatus('#{cc.clientId}:msg');
</script>
<div id="#{cc.clientId}:msg" class="#{cc.attrs.styleClass}"
style="display: none;#{cc.attrs.style}">
#{cc.attrs.text}
</div>
</cc:implementation>
Im Implementierungsteil werden zuerst benötigte Ressourcen geladen. Dazu zählen das Stylesheet components.css , die JavaScript-Bibliothek jsf.js und das Skript ajaxStatus.js mit der Funktionalität der Komponente. Anschließend wird über einen Aufruf der in ajaxStatus.js definierten Funktion registerAjaxStatus() ein Callback für die aktuelle Komponente registriert. Als Parameter bekommt diese Funktion die ID des div -Elements mit der Statusmeldung. Schließlich soll dieses Element während einer Ajax-Anfrage ein- und dann wieder ausgeblendet werden. Beachten Sie bei der ID einmal mehr den Zugriff auf #{cc.clientId} . Nur so ist gewährleistet, dass auch wirklich die von JSF gerenderte Client-ID zum Einsatz kommt. Das Ein- und Ausblenden ist ganz einfach über die CSS-Eigenschaft display realisiert, wobei das Element initial mit display: none im Attribut style versteckt ist.
Der eigentlich interessante Aspekt der Komponente ist aber der in Listing JavaScript für Kompositkomponente ajaxStatus dargestellte JavaScript-Code.
function processAjaxUpdate(msgId) {
function processEvent(data) {
var msg = document.getElementById(msgId);
if (data.status == "begin") {
msg.style.display = '';
} else if (data.status == "success") {
msg.style.display = 'none';
}
}
return processEvent;
};
function registerAjaxStatus(msgId) {
jsf.ajax.addOnEvent(processAjaxUpdate(msgId));
}
Um die Komponente einzusetzen, muss einfach nur das Tag <mc:ajaxUpdate/> in die Deklaration eingefügt werden - vorausgesetzt das Präfix mc ist entsprechend definiert.
6.4.2 Die Kompositkomponente ajaxPoll
Für manche Anwendungsfälle ist es notwendig, Bereiche einer Seite in periodischen Abständen zu aktualisieren. Klassische Beispiele dafür sind Seiten mit Börsenkursen, Auktionen oder aktuellen Sportergebnissen. JSF stellt diese Funktionalität zwar nicht direkt zur Verfügung, sie lässt sich aber mit wenigen Zeilen JavaScript-Code in einer Kompositkomponente realisieren. Erneut erweist sich das JavaScript-API als äußerst nützlich.Im Implementierungsteil werden zuerst die benötigten Ressourcen geladen. Dazu zählen die von JSF definierte JavaScript-Bibliothek jsf.js und das Skript ajaxPoll.js mit der notwendigen Funktionalität für die Komponente. Anschließend wird über einen Aufruf der in ajaxPoll.js definierten Funktion startAjaxPoll() das Polling gestartet. Als Parameter bekommt diese Funktion die ID des div -Elements, das über cc:insertChildren mit benutzerdefiniertem Inhalt gefüllt wird, und das Intervall. Beachten Sie bei der ID einmal mehr den Zugriff auf #{cc.clientId} , um die korrekte Client-ID zu erhalten. Listing Kompositkomponente ajaxPoll zeigt die Deklaration.
<cc:interface>
<cc:attribute name="interval" required="true"/>
</cc:interface>
<cc:implementation>
<h:outputScript name="jsf.js" library="javax.faces"
target="head"/>
<h:outputScript name="ajaxPoll.js"
library="mygourmet" target="head"/>
<script type="text/javascript">
startAjaxPoll('#{cc.clientId}',#{cc.attrs.interval});
</script>
<div id="#{cc.clientId}">
<cc:insertChildren/>
</div>
</cc:implementation>
function processPollEvent(interval) {
return function(data) {
if (data.status == 'success') {
startAjaxPoll(data.source.id, interval);
}
};
}
function poll(clientId, interval) {
var element = document.getElementById(clientId);
element.mgPoll = true;
jsf.ajax.request(element, null, {render: clientId,
onevent: processPollEvent(interval)});
}
function startAjaxPoll(clientId, interval) {
setTimeout("poll('"+clientId+"', "+interval+")", interval);
}
Einen kleinen Schönheitsfehler hat die Komponente noch. Wenn gleichzeitig ajaxStatus zum Einsatz kommt, wird bei jedem Update die Statusmeldung angezeigt - ein Verhalten, das nicht immer angebracht ist. Doch auch dafür gibt es eine sehr einfache Lösung. Wie Sie vielleicht schon bemerkt haben, wird in poll() dynamisch die Eigenschaft mgPoll auf das DOM-Element gesetzt. Diese Eigenschaft kann dann in der Callback-Funktion von ajaxStatus mit data.source.mgPoll abgefragt werden. Ist sie gesetzt, wird die Meldung nicht eingeblendet.
Um die Komponente einzusetzen, muss nur das Tag mc:ajaxPoll mit dem gewünschten Inhalt in die Deklaration eingefügt werden - vorausgesetzt das Präfix mc ist entsprechend definiert. Hier ein Beispiel, mit dem eine Art Uhr in die Ansicht eingebaut wird:
<mc:ajaxPoll interval="950">#{customerBean.time}</mc:ajaxPoll>
6.5 MyGourmet 14: Ajax
MyGourmet 14 ist vom Funktionsumfang her identisch mit MyGourmet 13 . Der große Unterschied liegt in der Integration von Ajax, wodurch an einigen Stellen ein komplettes Neuladen der Ansicht vermieden wird. Die Anwendung wirkt dadurch insgesamt flüssiger. Abbildung MyGourmet 14 mit Ajax-Status zeigt einen Screenshot der Ansicht showCustomer.xhtml mit aktivierter Ajax-Status-Meldung.Damit Benutzer immer über den Status einer Ajax-Anfrage informiert sind, fügen wir die Kompositkomponente ajaxStatus direkt im Template customerTemplate.xhtml in den Header ein. Listing Die Komponente ajaxStatusim Einsatz zeigt den aktualisierten Header-Bereich.
<ui:define name="header">
<h:graphicImage name="images/logo.png"/>
<h1>#{msgs.title_main}</h1>
<mc:ajaxStatus style="float:right; width: 100px;"/>
</ui:define>
Die Klasse DebugPhaseListener hat ebenfalls eine kleine Erweiterung bekommen. Die Logmeldungen zu Beginn und am Ende jeder Phase geben jetzt Auskunft darüber, ob es sich bei der Anfrage um eine Ajax-Anfrage handelt oder nicht. Um das festzustellen, rufen wir die Methode isAjaxRequest() des Partial-View-Contexts auf, der über den Faces-Context erreichbar ist. Listing Erweiterte Version des Debug-Phase-Listeners mit Ajax-Support zeigt den Sourcecode.
public class DebugPhaseListener implements PhaseListener {
private static final long serialVersionUID =
28697126271609506L;
private static Log log = LogFactory.getLog(
DebugPhaseListener.class);
public void afterPhase(PhaseEvent ev) {
String ajax = getAjaxText(ev.getFacesContext());
PhaseId phaseId = ev.getPhaseId();
log.debug("After phase: " + phaseId + ajax);
}
public void beforePhase(PhaseEvent ev) {
String ajax = getAjaxText(ev.getFacesContext());
PhaseId phaseId = ev.getPhaseId();
log.debug("Before phase: " + phaseId + ajax);
}
public PhaseId getPhaseId() {
return PhaseId.ANY_PHASE;
}
private String getAjaxText(FacesContext ctx) {
return ctx.getPartialViewContext()
.isAjaxRequest() ? " (Ajax)" : "";
}
}
In Abschnitt [Sektion: Ein erstes Beispiel mit f:ajax] haben wir bereits eine Lösung zum dynamischen Ein- und Ausblenden der Kreditkartendaten mittels f:ajax gezeigt. Die dort präsentierte Umsetzung hat allerdings noch einen kleinen Schönheitsfehler: Wenn im eingeblendeten Zustand die Kreditkartendaten geändert, ausgeblendet und wieder eingeblendet werden, gehen die Änderungen verloren. Ein genauerer Blick auf das eingesetzte f:ajax -Tag zeigt den Grund. Nachdem wir das Attribut execute nicht angegeben haben (und somit der Standardwert @this zum Einsatz kommt), bearbeitet JSF bei der partiellen Ausführung des Lebenszyklus nur das Auswahlfeld. Die geänderten Daten kommen nie am Server an und werden durch das erneute Rendern im Browser mit den alten Werten überschrieben.
Für das richtige Verhalten müssen wir nur das Attribut execute des f:ajax -Tags auf den Wert " @this ccType ccNumber" setzen. Jetzt werden bei der Ajax-Anfrage neben dem Auswahlfeld selbst auch die geänderten Daten der Komponenten mit den IDs ccType und ccNumber mitgeschickt und verarbeitet. Abbildung Einsatz von f:ajax zum Umschalten der Kreditkartendaten - Teil 2 zeigt die relevanten Teile von editCustomer.xhtml .
<h:panelGrid id="baseData" columns="2">
...
<h:selectBooleanCheckbox id="useCreditCard"
value="#{customerBean.customer.useCreditCard}"
valueChangeListener="#{customerBean.useCreditCardChanged}">
<f:ajax execute="@this ccType ccNumber" render="ccData"/>
</h:selectBooleanCheckbox>
</h:panelGrid>
<h:panelGrid id="ccData" columns="2">
...
<h:selectOneListbox id="ccType" ... />
...
<h:inputText id="ccNumber" ... />
</h:panelGrid>
6.6 Werkzeuge für den Ajax-Entwickler
Ajax ist durch die Vielzahl an verwendeten Basistechnologien nicht gerade einfach einzusetzen. Will man Ajax-Anwendungen bauen, ist eine Unterstützung durch geeignete Entwicklungswerkzeuge unabdingbar. Die folgende Aufzählung von Tools erhebt keinen Anspruch auf Vollständigkeit. Wir wollen Ihnen eine Reihe von Werkzeugen präsentieren, die sich in der täglichen Arbeit mit JSF-Projekten bewährt haben.6.6.1 Firebug
FirebugFirebug ist unter http://getfirebug.comund als Add-on zu Firefox erhältlich.: ist eine Erweiterung von Firefox , die eine ganze Reihe sehr nützlicher Werkzeuge für Webentwickler direkt in den Browser integriert. Firebug ist frei verfügbar und erweist sich in vielen Situationen als unbezahlbar. Besonders dann, wenn es darum geht, den DOM-Baum zu analysieren oder JavaScript-Code zu debuggen. Hier eine Liste der wichtigsten Features:- Inspizieren und Editieren von HTML-Code
- Inspizieren und Editieren von CSS-Regeln
- Debuggen und Profiling von JavaScript-Code
- Analysieren des DOMs
- Analysieren des HTTP-Verkehrs
6.6.1.1 Analyse des DOM-Baums
Versucht man die Aktualisierung durch die Ajax-Antwort mit einem Editor nachzuvollziehen, wird keine Änderung des HTML-Codes sichtbar sein. Die Webseite wurde nicht komplett neu geladen, sondern nur der DOM-Baum aktualisiert. Diesen DOM-Baum rendert der Browser und stellt ihn grafisch dar. Die Veränderung kann nur durch die Visualisierung des Baumes selbst sichtbar gemacht werden. Firebug bietet die visuelle Darstellung des Baumes der HTML-Elemente in Form einer Verzeichnisstruktur. Abbildung Firebug mit aktualisierter Collapsible-Panel-Komponente zeigt die Ansicht showCustomer.xhtml mit eingeklapptem Adressen-Panel und aktiviertem Firebug .Es ist auch möglich, Knoten über deren ID, Tag-Name oder Attribute zu suchen, diese im Browser herausheben zu lassen oder deren Eigenschaften zu ändern. Firebug zeigt aber nicht nur den aktuellen HTML-Code, sondern hebt sogar Elemente farblich hervor, die sich gerade geändert haben.
Im unteren Panel in Abbildung Firebug mit aktualisierter Collapsible-Panel-Komponente ist der mit der Webseite synchron gehaltene DOM-Baum zu sehen. Das hervorgehobene Element ist der div -Block des Panels, in dem die Liste der Adressen angezeigt wird. Bei einer initialen Anfrage auf die Seite ist das Panel immer ausgeklappt. Der in der Abbildung erkennbare, eingeklappte Zustand ist erst als Reaktion auf die Ajax-Anfrage nach dem Klick auf das Icon eingetreten.
Sobald man in der Baumansicht ein Element anwählt, wird dieses im Browser farblich hervorgehoben. Es ist auch möglich, direkt aus dem Browserfenster ein Element anzeigen zu lassen. Auf der rechten Seite sind zusätzliche Informationen über die Knoten, wie Name, ID oder die Eigenschaften, abrufbar. Es gibt auch die Möglichkeit, in eine JavaScript-Objektansicht umzuschalten. Wie in Abbildung Ansicht mit Attributen und Methoden in Firebug zu sehen, kann in sämtliche Methoden und Attribute eines JavaScript-Objektes Einsicht genommen werden.
Auch wenn Sie den Internet Explorer einsetzen, müssen Sie nicht auf einen DOM-Inspektor verzichten. In Version 8 ist ein entsprechendes Werkzeug sogar bereits im Standardlieferumfang enthalten. Für ältere Versionen empfiehlt sich die Internet Explorer Developer ToolbarDie Internet Explorer Developer Toolbar ist unter der Adresse http://www.microsoft.com/downloads erhältlich.: .
6.6.1.2 JavaScript-Debugging
Ein unersetzliches Werkzeug für Ajax-Entwickler ist ein JavaScript-Debugger, wie ihn zum Beispiel Firebug für Firefox bietet. Mit diesem kann zur Laufzeit JavaScript-Code der Webseite oder der Ajax-Bibliothek in einzelnen Schritten durchlaufen werden. So wird komplexer Code leichter verständlich, Objekte, ihre Daten und Methoden erkennbar und fehlerhaftes Verhalten einfach ermittelbar. Wie in herkömmlichen Debuggern ist es möglich, Breakpoints zu setzen und sich an dieser Stelle der Ajax-Applikation den Zustand von Variablen und Objekten anzusehen und Funktionen aufzurufen. Ein Praxisbeispiel ist in Abbildung JavaScript-Debugging in Firebug zu sehen.Hier wurde ein Breakpoint in das Skript inputSpinner.js gesetzt. Sobald der Benutzer auf eines der Bilder zum Erhöhen oder Reduzieren des Werts klickt, springt das Fenster des Debuggers auf und die Abarbeitung des Codes hält genau an dieser Stelle an. Im Fenster Überwachen kann jeder erdenkliche JavaScript-Befehl eingegeben werden. Hier zum Beispiel der Code, um das Input-Spinner-Eingabefeld anzuzeigen:
document.getElementById('form:stars')
Für den Internet Explorer ist der Microsoft Script DebuggerMicrosoft Script Debugger ist unterhttp://www.microsoft.com/downloadserhältlich.:
als Freeware erhältlich, der wie Firebug eine
Call-Stack-Navigation besitzt und zusätzlich JavaScript während des Debuggens
ausführen kann. In Version 8 verfügt der Internet Explorer bereits im
Standardlieferumfang über ein recht brauchbares Entwicklerwerkzeug mit DOM-Browser
und JavaScript-Debugger.6.6.2 HTTP-Debugger
Manchmal kann es recht nützlich sein, sich den Protokollablauf ein wenig näher anzusehen. Mit einem HTTP-Debugger ist es möglich, den kompletten HTTP-Verkehr mitzuschneiden. Eines der bekanntesten Werkzeuge in diesem Bereich ist der frei verfügbare HTTP-Debugger Fiddler von Microsoft Fiddler ist unter http://www.fiddlertool.com erhältlich.: . Die Zusammenarbeit mit dem Browser wird über das Programm selbst geregelt - es stellt einen lokalen Proxy dar. In Firefox muss der Proxy unter den Verbindungseinstellungen mit den Daten 127.0.0.1 und Port 8888 eingetragen werden. Im Internet Explorer sind keine weiteren Einstellungen zu treffen, denn die Zwischenstelle wird automatisch erkannt. Fiddler kann so konfiguriert werden, dass das Programm die Abarbeitung vor einer HTTP-Anfrage oder nach einer HTTP-Antwort - ähnlich einem gewöhnlichen Debugger - anhält und so der aktuelle Stand der Interaktion zu sehen ist. Dieser wird im linken Fenster von Fiddler protokolliert, wie es Abbildung Der HTTP-Debugger Fiddler protokolliert den HTTP-Verkehr mit. Hier ist eine Ajax-Antwort zu sehen. zeigt. In Version 2 ist es sogar möglich, HTTPS-Verbindungen zu debuggen.
Abbildung:Der HTTP-Debugger Fiddler protokolliert den
HTTP-Verkehr mit. Hier ist eine Ajax-Antwort zu sehen.
Für den Firefox-Browser existiert die Erweiterung Live HTTP HeadersLive HTTP Headers ist als Add-on zu Firefox und unter der Adresse http://livehttpheaders.mozdev.org erhältlich.: , die aber nur einen Teilbereich der Funktionalität von Fiddler bietet, zum Beispiel speichert sie keinen HTTP-Body mit. Firebug bietet mittlerweile auch eine sehr brauchbare Übersicht aller abgesetzten HTTP-Requests und ermöglicht das einfache Umschalten zwischen "vollen" und Ajax-Requests.
6.6.3 Web Developer Toolbar
Ein für den Webentwickler unersetzliches Werkzeug ist die Web Developer ToolbarWeb Developer Toolbar ist als Add-on zu Firefox und unter der Adresse http://chrispederick.com/work/webdeveloper/ erhältlich.: des Firefox-Browsers. Sie stellt ebenfalls eine Erweiterung dar und integriert sich als eigenes Modul unterhalb der Adressleiste. Grob umrissen bietet sie folgende Funktionen an:- Grafische Auszeichnung von einzelnen HTML-Elementen
- Validierung von HTML, CSS und anderen Technologien
- Formatierte Anzeige des Quellcodes
- Frei definierbare Größe des Browserfensters
- Visuelle Ausgabe von HTML-Attributen
- Manipulation von Formularen
- Anzeige der CSS-Stile einzelner HTML-Elemente sowie aller externen CSS-Dateien
- Editieren von CSS und HTML und Anzeigen der Änderungen in Echtzeit (seit Version 1.0)