Verwendung von eindeutigen IDs in JSF2-Naming-Containern

JSF2 bietet mit dem <f:ajax>-Tag wirklich einfach zu verstehende aber trotzdem mächtige Ajax-Funktionen. Die ersten einfachen Versuche gelingen meist innerhalb weniger Minuten und man glaubt dies quasi sofort in eigenen Projekten verwenden zu können.

Mein erster Versuch Ajax in einem JSF2-Projekt für einen Kunden einzusetzen hat mir aber bei der ersten relativ komplexen Seite zumindest für ein bis zwei Stunden eine Menge Kopfzerbrechen bereitet. Dabei ist das Problem reinste Unkenntnis gewesen, weil die wenigsten Tutorials deutlich darauf hinweisen.

Aber was war überhaupt passiert?

Ich hatte eine recht komplexe JSF-Seite erstellt, die über den Facelet-Template-Mechanismus aus mehr als 10 einzelnen XHTML-Seiten gerendert wurde. Eine Datei enthielt einen Primefaces-Dialog mit einer bestimmten ID, der in einer völlig anderen XHTML manipuliert werden sollte. Genauer: nach Klick auf einen Button sollte ein Ajax-Request Daten aus der Datenbank nachladen, die danach in diesem Dialog angezeigt werden sollten.

Der Ajax-Request wurde korrekt abgesetzt, die Daten wurden geladen (über Breakpoints sichtbar) und der Dialog wurde auch geöffnet, allerdings enthielt er keine Daten. Es sah so aus, als wenn er weiter im jungfräulichen Auslieferungszustand wäre. Irgendetwas verhinderte als das neu-rendern des Dialogs.

Nach ein bis zwei Stunden rumrätseln und googeln, sind uns aber die Schuppen von den Augen gefallen und wir machten Bekanntschaft mit dem Konzept der NamingContainer.

Wenn eine JSF-Komponente das NamingContainer-Interface implementiert ist dies eine natürlich Grenze innerhalb derer Komponenten-IDs eindeutig sein müssen und auch sind. Alles was außerhalb des NamingContainers im Komponentenbaum existiert, kann dieselbe ID haben wie eine Komponente innerhalb des NamingContainers. Um trotzdem auf diese äußeren Komponenten zugreifen zu können, muss die ID “fully qualified” vom UIViewRoot aus gesehen angegeben werden. Die einzelnen NamingContainer werden dabei normalerweise durch einen Doppelpunkt getrennt. Die ID muss also in der Form “:ID:ID:ID” angegeben werden. Gestartet wird mit dem Doppelpunkt des UIViewRoot und danach jede ID einer Komponente die einen NamingContainer implementiert.

Die häufigsten Komponenten, die man so benutzt und einen eigenen NamingContainer darstellen sind <h:form>, <h:dataTable> und jede Composite Component. Bei Komponenten aus einer Komponentenbibliothek hängt es von dessen Hersteller ab, ob eine Komponente einen NamingContainer implementiert.

Ein Beispiel:

	<h:form id="form">
		<h:outputText value="Namen eingeben:" />
		<h:inputText value="#{testBean.name}" />
		<h:commandButton value="Abschicken" action="#{testBean.speichern}">
			<f:ajax render=":form:panel:name" />
		</h:commandButton>
	</h:form>
	<et:myPanel id="panel">
		<h:outputText id="name" value="Ihr Name: #{testBean.name}" />
	</et:myPanel>

Der Code zeigt ein Eingabefeld und einen Button innerhalb einer Form an und außerhalb der Form wird über eine Composite Component ein Panel gerendert, das den eingegebenen Namen anzeigen soll. Im <f:ajax>-Tag darf man nun nicht nur die ID “name” angeben, sondern die komplette ID inkl. der IDs der Form und der Composite Component, weil beide einen NamingContainer implementieren.

Übrigens lässt sich der Trenner zwischen den einzelnen IDs auch umkonfigurieren. Dazu muss man den Parameter “javax.faces.SEPARATOR_CHAR” in der web.xml entsprechend setzen.

Mehr Informationen über NamingContainer und Komponenten-IDs finden sich bei Illegal Argument Exception

Leave a Reply

Your email address will not be published. Required fields are marked *

*