JSF unordered list mit Buttons aus rekursiver Datenstruktur erzeugen

Eigentlich ein einfaches Problem, als JSF-Neuling kostet es aber doch gerade zuviel Zeit für meinen Geschmack :suspect:

Gegeben ist folgende Datenstruktur:


	private List<Foo> children;
	
	private Bar bar;

	public List<Foo> getChildren() {
		return children;
	}

	public Bar getBar() {
		return bar;
	}
	
}```

children kann leer sein, bar kann null sein. 
Falls bar nicht null ist, kann es für eine Aktion genutzt werden

Diese Struktur soll jetzt wie folgt dargestellt werden:
Jedes Element wird als Eintrag in einer Liste gerendert, angezeigt wird ein identifier und ein Button, der eine Aktion mit bar durchführt.

Die Datenstruktur hat im Moment eine Tiefe von 4, was sich nicht mehr großartig ändern dürfte, allerdings drehts mir bei dem Code hier den Magen um (DRY und so...)

[XML]<ul>
	<ui:repeat var="foo" value="#{FooManagerBean.foos}">
		<h:panelGroup>
			<li>
				#{foo.name}
				<h:form rendered="#{! empty foo.bar}">
					<h:commandButton value="bar"
						action="#{FooManagerBean.barAction(foo.bar)}" />
				</h:form>
			</li>
		</h:panelGroup>
		<ul>
			<ui:repeat var="subfoo" value="#{foo.children}">
				<h:panelGroup>
					<li>
						#{subfoo.name}
						<h:form rendered="#{! empty subfoo.bar}">
							<h:commandButton value="bar"
								action="#{FooManagerBean.barAction(subfoo.bar)}" />
						</h:form>
					</li>
				</h:panelGroup>
				<ul>
					<ui:repeat var="subsubfoo" value="#{subfoo.children}">
						<h:panelGroup>
							<li>
								#{subsubfoo.name}
								<h:form rendered="#{! empty subsubfoo.bar}">
									<h:commandButton value="bar"
										action="#{FooManagerBean.barAction(subsubfoo.bar)}" />
								</h:form>
							</li>
						</h:panelGroup>
						<ul>
							<ui:repeat var="subsubsubfoo" value="#{subsubfoo.children}">
								<h:panelGroup>
									<li>
										#{subsubsubfoo.name}
										<h:form rendered="#{! empty subsubsubfoo.bar}">
											<h:commandButton value="bar"
												action="#{FooManagerBean.barAction(subsubsubfoo.bar)}" />
										</h:form>
									</li>
								</h:panelGroup>
								<ul>
									<h:outputText rendered="#{! empty subsubsubfoo.children}"
										value="... (missing values)" />
								</ul>
							</ui:repeat>
						</ul>
					</ui:repeat>
				</ul>
			</ui:repeat>
		</ul>
	</ui:repeat>
</ul>[/XML]

Was ich gerne schreiben würde, wäre etwas in der Art (Pseudocode):
[XML]<snippet name="snippet" parameterValue="param">
	<li>
		#{param.name}
		<h:form rendered="#{! empty param.bar}">
			<h:commandButton value="bar"
				action="#{FooManagerBean.barAction(param.bar)}" />
		</h:form>
	</li>
	<ul>
		<ui:repeat var="child" value="#{param.children}">
			<!-- Snippet in sich selbst einfügen, mit anderem Parameter -->
			<renderSnippet value="snippet" param="child" />
		</ui:repeat>
	</ul>
</snippet>[/XML]

Kennt jemand eine elegantere Lösung/Ansatz für das Problem?
Mit Templates und Compositions habe ich sowas leider nicht hinbekommen, scheint mir dafür auch nicht ganz der Anwendungsfall zu sein.

So wie es im Moment ist funktioniert es zwar, aber ich würde es ungerne so lassen :D.

Gruß

Auslagern in einer Composite Component. Diese kann sich (meines Wissen nach) auch selbst einbetten. Dann geht das auch rekursiv.

Hat funktioniert, falls jemand ein ähnliches Problem hat:

Das Tutorial hier war brauchbar für Composites: http://www.mkyong.com/jsf2/composite-components-in-jsf-2-0/

Aufruf aus der ursprünglichen Seite:
[XML]


    <c:forEach var=“foo” items="#{FooManagerBean.foos}">
    <myproj:mycomposite fooEntry="#{foo}" />
    </c:forEach>
[/XML]

Und das composite mycomposite:
[XML]composite:interface

<composite:attribute name="fooEntry" />

</composite:interface>

composite:implementation

<li>#{cc.attrs.fooEntry.name}
            <h:form rendered="#{! empty cc.attrs.fooEntry.bar}">
                <h:commandButton value="bar"
                    action="#{FooManagerBean.barAction(cc.attrs.fooEntry.bar)}" />
            </h:form>
</li>
<c:if test="#{! empty cc.attrs.fooEntry.children}">
	<ul>
		<ui:repeat var="child" value="#{cc.attrs.fooEntry.children}">
			<myproj:mycomposite regionEntry="#{child}" />
		</ui:repeat>
	</ul>
</c:if>

</composite:implementation>[/XML]

Hatte zwischenzeitlich Probleme, dass Variablen nicht Sichtbar waren, bzw Stackoverflow als ich per rendered= den Rekursionsanker gebaut habe, das kriegt man aber mit den jstl-tags c:forEach bzw c:if ganz gut in den Griff.

Gruß

Statt <c:forEach kann man auch eine <p: DataTable verwenden. Dann braucht man nicht auf die JSP Libary zu referenzieren.

Ich glaube du meinst zum 1. eine DataList, und zum 2. benutzt er kein Primefaces, sondern Plain JSF :wink:

Ist Plan JSF mit JSP nicht ein widerspruch in sich? :slight_smile:

Macht für mich im Moment keinen Unterschied, solange etwas Ausführbares rauskommt mit dem ich arbeiten kann.
Über Primefaces und Konsorten bin ich natürlich auch schon gestolpert, kann sein, dass ich noch darauf umsteige.