World Wide Wicket 2.0

Eine strukturierte Sache – Templates und Vererbung

Alle Seiten der Anwendung basieren auf demselben Layout. Herr K. könnte jetzt natürlich das vorhandene Template für alle Seiten duplizieren und entsprechend anpassen. Dies würde die Wartbarkeit der Anwendung jedoch dramatisch verschlechtern, da bei einer strukturellen Layoutanpassung alle Seiten der Anwendung angepasst werden müssten. Herr K. recherchiert ein wenig unter [4] und findet heraus, dass Wicket für genau dieses Problem bereits eine passende Lösung bereitstellt – die Templatevererbung. Um Templatevererbung in der Anwendung nutzen zu können, leiten alle Seiten von der gleichen abstrakten WebPage ab. Hierfür implementiert Herr K. die Klasse AbstractVideoStorePage:

public abstract class AbstractVideoStorePage extends WebPage {
public AbstractVideoStorePage(){
super();
}
}

Zusätzlich definiert Herr K. das zugehörige HTML-Template in Listing 2.

Listing 2

PENTASYS AG - K's Video Store Application

Herr K. lernt Wicket - Ihre Online Videothek

Die in diesem Template definierten Layoutelemente (Seitentitel, Headline und Navigation) sollen in allen Seiten angezeigt werden. Im Template definiert Herr K. zusätzlich das Element <wicket:child/>. Dieses Element definiert die Position im Seitenlayout, an der von AbstractVideoStorePage abgeleitete Seiten ihre Elemente platzieren können.

Bisher hatte Herr K. lediglich die Anmeldeseite für Kunden fertig gestellt. Da auch auf dieser die in der AbstractVideoStorePage definierten Elemente erscheinen sollen, nimmt Herr K. einige Anpassungen vor. Zunächst passt Herr K. das zugehörige HTML-Template wie folgt an:

[...]

Außerdem leitet sich die Klasse HomePage nun von AbstractVideoStorePage ab:

public class HomePage extends AbstractVideoStorePage {
public HomePage(final PageParameters parameters) {
/*
Hier werden von nun an lediglich die Seitenspezifischen Komponenten definiert
*/
}}

Zuletzt definiert Herr K. das Element <wicket:extend>. Jegliches Markup, das außerhalb des <wicket:extend/>-Elements definiert ist, wird verworfen und durch das Markup aus der Oberklasse ersetzt. Alle Elemente innerhalb dieses Elements werden auf der aktuellen Seite gerendert.

ListViews und die Navigation

Herr K. freut sich über die saubere Lösung und macht sich im Anschluss direkt daran, die Navigation zu definieren (Abb. 1).

Abb. 1: Navigation mit ListViews

Zunächst definiert sich Herr K. die folgende Hilfsklasse MenuEntry:

public class MenuEntry implements Serializable {
public MenuEntry(Class extends WebPage> targetPage,String displayName) {
super();
this.targetPage = targetPage;
this.displayName = displayName;
}
/*
Getter und Setter
*/
}

Diese Klasse dient Herrn K. als Modell für die Navigation. Sie erwartet den Namen der angezeigt werden soll (displayName) und ein Class-Objekt vom Typ WebPage (targetPage) für die Zielseite, auf die der Navigationspunkt verweisen soll. Um die Navigation implementieren zu können, muss sich Herr K. noch etwas genauer mit dem Konzept der Repeater vertraut machen. Diese schaffen eine einfache Möglichkeit, Listen dynamisch zu rendern. Wicket bietet mehrere Repeater-Implementierungen an. Im Folgenden wird Herr K. die Klasse ListView verwenden. Er definiert folgendes Markup für die Navigation:

Ein ListView erwartet sowohl eine Komponenten-ID als auch ein Listenmodell im Konstruktor. Herr K. erzeugt sich eine neue Instanz eines ListViews im Konstruktor der AbstractVideoStorePage (Listing 3) und übergibt eine Liste an MenuEntries, die er in einer eigenen Methode erzeugt. Doch wozu benötigt er das Element <wicket:container/> im Markup?

Listing 3
add(new ListView("navigationList", getMenuEntries()) {
protected void populateItem(ListItem item) {
BookmarkablePageLink entryLink = new BookmarkablePageLink("entry",item.getModelObject().getTargetPage());
entryLink.add(new Label("title", item.getModelObject()
.getDisplayName()));
item.add(entryLink);
}
});

ListView wiederholt die zugehörigen Markup-Elemente (in diesem Fall das Element <wicket:container/> und alle untergeordneten Tags). Rein intuitiv wollte Herr K. ListView dem übergeordneten <div/>-Tag zuordnen, dies hätte aber zur Folge, dass das Element <div class=“navigation“/> für jedes Element in der Liste wiederholt werden würde. Wiederholt werden soll aber nur das entsprechende Link-Element.

Natürlich hätte Herr K. das <a/>-Tag auch mit einem einfachen <span/>-Element umgeben und im zugehörigen Java-Code einen Container (Klasse WebMarkupContainer) erzeugen können. Damit würde Herr K. aber seinen Templatecode vollspannen. Viel besser ist in diesem Fall die Verwendung des <wicket:container/>-Tags, das einen impliziten Container erzeugt, und im Produktiveinsatz im Template überhaupt nicht mehr erscheint (läuft Wicket im Deployment-Modus werden alle Tags im Wicket-Namespace automatisch ausgeblendet).

Der ListView ruft nun für jede MenuEntry-Instanz in der übergebenen Liste die Methode populateItem(ListItem<MenuEntry> item) auf. Als Parameter wird hier ListItem übergeben, das den Container repräsentiert, der zuvor mit <wicket:container/> erzeugt wurde. Diesem fügt Herr K. in jeder Iteration eine Instanz eines BookmarkablePageLink hinzu (Achtung: Der Aufruf muss item.add(…)und nicht nur add(…)lauten!). Die Klasse BookmarkablePageLink erwartet im Konstruktor bereits eine WebPage, auf die verzweigt werden soll. Diese bekommt Herr K. aus dem übergebenen MenuEntry-Objekt, auf das mit item.getModelObject()direkt zugegriffen werden kann.

Zuletzt fügt Herr K. der erzeugten Link-Komponente noch ein Label hinzu, dem er als Modell den entsprechenden Titel des Navigationspunktes übergibt (menuEntry.getDisplayName()). Doch Moment, da fehlt noch was: Die Navigation sollte erst dann sichtbar sein, wenn sich der Kunde tatsächlich über das Registrierungsformular registriert hat. Nichts einfacher als das. Herr K. überschreibt einfach die isVisible()-Methode des ListViews:

public boolean isVisible() {
return VideoSession.get().getCustomer() != null;
}

Dadurch wird sichergestellt, dass die Navigation wirklich nur dann sichtbar ist, wenn ein Kunde in der Session gespeichert wurde.

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.