Reply to comment

Animierte RadioLists mit dem RadioList Tag

In der aktuellen Revision #52 ist eine neue Klasse RadioListTag hinzugekommen. Diese stellt eine einfache, abstrakte Basisklasse für Tags dar, die zur Ausgabe von Auswahllisten genutzt werden kann.

Die Auswahllisten sind oftmals gleichartig strukturiert: Man hat eine Liste von Einträgen, von denen man genau einen aussuchen soll. Damit die Liste nicht zu aufgebläht wird, werden die Informationen "versteckt". Erst bei einem Klick auf den Listeneintrag werden sie angezeigt.

Der RadioListTag nimmt einem nun eine Menge Arbeit ab. Um einen eigenen Listen-Tag zu erstellen, leitet man einfach eine eigene Klasse von ihm ab:

package housemanagement.administration.tags;

import java.util.Iterator;
import java.util.Set;

import users.UserManager;
import housemanagement.WebPortal;
import housemanagement.tags.RadioListTag;
import housemanagement.users.PortalUser;

public class PrintUsers extends RadioListTag {

        private static final long serialVersionUID = 1L;
        private Set<String> userNames;
        private Iterator<String> it;
        private PortalUser currentUser;

        public PrintUsers() {
                super();
                userNames = UserManager.getGlobalUM().getUserNames();
                it = userNames.iterator();
        }
       
        public void beginNext() {
                currentUser = (PortalUser) UserManager.getGlobalUM().getUser(it.next());
        }

        public String currentBody() {
                Object args[] = { currentUser.getProfile().getFirstName(),
                                currentUser.getProfile().getName(),
                                currentUser.isDeleted() };
                return WebPortal.getMessageResource("hm.tags.rlt.printusers.body", args);
        }

        public String currentId() {
                return currentUser.getName();
        }

        public String currentTitle() {
                return currentUser.getName();
        }

        public Boolean hasNext() {
                return it.hasNext();
        }
}

Den Konstruktor sollte man nutzen, um sich bspw. einen Iterator für die Liste zu holen, deren Inhalt man ausgeben will.

Wichtig sind dann die restlichen Methoden:

hasNext() wird aufgerufen um nachzufragen, ob weitere Items auszugeben sind. Hier bestenfalls den Rückgabewert des Iterators zurückgeben.

beginNext() sollte dann dazu genutzt werden, um den nächsten auszugebenden Eintrag zwischenzuspeichern.

Die Methode currentId() sollte die ID des aktuellen Items ausgeben, hier also bestenfalls item.getName() aufrufen, da diese Methode bereits einzigartige Werte liefern sollte. currentTitle gibt den Wert zurück, der später in der Liste dann auftaucht. Im Beispiel wird hier ebenfalls die ID ausgegeben, allerdings bietet es sich an, hier noch ein paar zusätzliche Infos mit auszugeben.
Schließlich gibt es noch currentBody(). Diese Methode sollte die Inhalte zurückgeben, die dann im aufklappbaren Abschnitt auftauchen. Im Beispiel wird hier noch ein schöner Kunstgriff verwendet. Und zwar findet sich der Inhalt schon vorformatiert in der MessageResources:

# Print Users Tag
hm.tags.rlt.printusers.body=\
<table>\
        <tr>\
                <td align="left">\
                        Vorname:\
                </td>\
                <td align="left">\
                        {0}\
                </td>\
        </tr>\
        <tr>\
                <td align="left">\
                        Nachname:\
                </td>\
                <td align="left">\
                        {1}\
                </td>\
        </tr>\
        <tr>\
                <td align="left">\
                        Gelöscht:\
                </td>\
                <td align="left">\
                        {2}\
                </td>\
        </tr>\
</table>

Im Tag selbst wird nun die statische Methode WebPortal.getMessageResources() genutzt, um den entsprechenden Eintrag auszulesen. Dabei wird eine Liste mit Inhalten übergeben, die dann entsprechend an den Stellen {0} - {2} eingesetzt werden.

Um den eigens erstellten Tag dann nutzen zu können, einfach folgendes in die Datei WEB-INF/tlds/housemanagement.tld eintragen:

        <tag>
                <name>PrintUsers</name>
                <tag-class>housemanagement.administration.tags.PrintUsers</tag-class>
                <body-content>empty</body-content>
        </tag>

Danach kann man den Tag einfach in einer JSP nuzten:

<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<%@ taglib uri="/tags/struts-logic" prefix="logic" %>
<%@ taglib uri="/tags/webpoint" prefix="wp" %>
<%@ taglib uri="/tags/housemanagement" prefix="hm" %>

<h1>
        <bean:message key="housemanagement.admin.viewusers.caption"/>
</h1>

<html:form action="/ViewUsersAction">
       
        <hm:PrintUsers/>
        <table>
                <tr>
                    <td align="center">
                   <html:submit property="method">
                       <bean:message key="housemanagement.admin.viewusers.resetpassword.caption"/>
                   </html:submit>
            </td>
            <td align="center">
                    <html:submit property="method">
                        <bean:message key="housemanagement.admin.viewusers.deleteuser.caption"/>
                    </html:submit>
            </td>
                </tr>
        </table>
</html:form>

UPDTAE

In der neuesten Revision gibt es eine neue Datei TagResources.properties. Diese sollte dazu genutzt werden, die Tag-Grundgerüste abzulegen. Damit bleibt die eigentliche Message-Resources weiterhin sauber während wir Java- und HTML-Code ebenfalls trennen können.

Außerdem sollte in der TagResources kein übersetzbarer Text mehr sein! Sprich: Bezeichnungen, die übersetzt werden sollten ebenfalls durch Platzhalter ersetzen, eine Übersetzung in der MessageResources einfügen und durch die Tag-Klasse die Einträge aus der MessageResources auslesen und in das Gerüst aus der TagResources einfügen lassen.

UPDATE #2

So, weitere Neuigkeiten:
Daten dürfen nicht im Konstruktor des Tags initialisiert werden. Warum? Anscheinend gibt es immer genau eine Instanz des Tags, die dann im Speicher gehalten (zumindest aber kurz gecached) wird. D.h. z.B. auf obiges Beispiel bezogen:
Nachdem der Tag zwar anfangs zu funktionieren scheint, wird er bei wiederholtem Aufruf keine Benutzer mehr darstellen! Der Grund ist, das eben intern noch der alte Iterator verwendet wird, der zwischenzeitlich aber nur noch "false" beim Aufruf von getNext() zurückliefert. Damit wird auch nichts mehr dargestellt.

Um das ganze zu umgehen, gibt es nun eine weitere abstrakte Methode, die implementiert werden muss: initializeData().
Einfach die benötigten Daten statt im Konstruktor in dieser Methode initialisieren und fertig ;)

Reply

  • Use [toc list: ol; title: Table of Contents; minlevel: 2; maxlevel: 3; attachments: yes;] to insert a mediawiki style collapsible table of contents. All the arguments are optional.
  • Allowed HTML tags: <del> <a> <em> <strong> <strike> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <span> <pre> <h1> <h2> <h3> <h4> <h5> <h6> <!--tableofcontents--> <sub> <sup> <table> <tr> <td> <th> <blockquote> <br> <p> <object> <embed> <param>
  • Lines and paragraphs break automatically.
  • Images can be added to this post.
  • Pairs of<blockquote> tags will be styled as a block that indicates a quotation.
  • This is an example format which provides a wikimedia-style input format.
  • Use [fn]...[/fn] (or <fn>...</fn>) to insert automatically numbered footnotes.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. The supported tag styles are: <foo>, [foo], [[foo]].
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.
Copyright (c) RPdev 2008 - 2011