JSF selectOneRadio-/selectManyCheckBox-Items gruppieren

gedanke

Mitglied
Hallo allerseits!

Ich probiere seit langem, die Items der Komponenten selectManyCheckbox/selectOneRadio für den Nutzer nach einem Property zu gruppieren. Also für den Nutzer sollte es so aussehen:

Code:
    Mercedes    VW      ...  
    car 1       car 1   ...  
    car 2       car 2   ...  
    car 3       car 3   ...

Alle sechs Items (in diesem Beispiel) kommen natürlich von einem einzigen Property, das List<Auto> liefert. Also das Datenmodell (die Datenquelle) ist "normal" - keine Angst. :)

Meine Versuche führten über Tomahawks spread-Attribut. Darüber könnte ich für jede Automarke die Items als eigenen dataTable darstellen. Jedoch passiert dabei folgendes:

Code:
    Mercedes    VW      ...  
    car 1     
                car 1   ...  
                car 2   ...  
    car 2      
                car 3   ...  
    car 3

Mir ist klar, warum das passiert. Ich nutze in jedem dataTable im outputText
Code:
rendered="#{auto.marke eq 'Mercedes'}"
(und analog mit VW und anderen Marken).

Weiß jemand, mit welcher Methode ich diese "Lücken" wegkriege?

Ich nutze JSF 2 mit aktuellstem Tomahawk und PrimeFaces.

Für Hilfe meinen Dank!
 

F.S.WhiTeY

Bekanntes Mitglied
Musste auf CSS oder nen Tabellenlayout zurückgreifen. Wenn du nicht klarkommst, stell dein Template ein und ich machs dir..

EDIT:
natürlich funktioniert das mit dem Datatabel dann nicht ;)
 
Zuletzt bearbeitet:

gedanke

Mitglied
Geht das mit CSS oder 'ner Tabelle? Die Automarken (in dem Beispiel) sind mir bekannt und könnten ruhig hart kodiert sein, aber die Anzahl der einzelnen Autos pro Marke ist erst zur Laufzeit bekannt. Aber jede Lösung ist mir lieb!

So mache ich es momentan:
Code:
		<t:selectManyCheckbox id="autos" layout="spread" forceId="true" forceIdIndex="false" value="#{handler.selectedAutos}" required="true">
			<f:selectItems value="#{autoHelper.autos}" var="auto"
				itemLabel="#{auto.shortname}" />
		</t:selectManyCheckbox>

		<h:panelGrid columns="4">
			
			<t:dataTable var="row" value="#{autoHelper.autos}"
				rowIndexVar="index">
				<h:column>
					<f:facet name="header">
						<t:outputText value="Marke A" />
					</f:facet>
					<t:checkbox for=":#{form}:autos" index="#{index}"
						rendered="#{row.marke eq 'A'}" />
				</h:column>
			</t:dataTable>

			<t:dataTable var="row" value="#{autoHelper.autos}"
				rowIndexVar="index">
				<h:column>
					<f:facet name="header">
						<t:outputText value="Marke B" />
					</f:facet>
					<t:checkbox for=":#{form}:autos" index="#{index}"
						rendered="#{row.marke eq 'B'}" />
				</h:column>
			</t:dataTable>

			<t:dataTable var="row" value="#{autoHelper.autos}"
				rowIndexVar="index">
				<h:column>
					<f:facet name="header">
						<t:outputText value="Marke C" />
					</f:facet>
					<t:checkbox for=":#{form}:autos" index="#{index}"
						rendered="#{row.marke eq 'C'}" />
				</h:column>
			</t:dataTable>

			<t:dataTable var="row" value="#{autoHelper.autos}"
				rowIndexVar="index">
				<h:column>
					<f:facet name="header">
						<t:outputText value="Marke D" />
					</f:facet>
					<t:checkbox for=":#{form}:autos" index="#{index}"
						rendered="#{row.marke eq 'D'}" />
				</h:column>
			</t:dataTable>
			
		</h:panelGrid>

Wenn es ohne die vier dataTables geht wäre das super, aber die ausgewählten Autos müssen irgendwie im value von selectManyCheckbox landen. Meine Lösung hat eben die doofen oben beschrieben Lücken.

Für deine Hilfe ist dir mein ewiger Dank sicher!
 

F.S.WhiTeY

Bekanntes Mitglied
Ok ich hab da ne Idee. Ich nutze zwar kein Primefaces und auch kein Tomhawk, aber dein Problem lässt sich mit reinen JSF 2 Komponenten lösen. Das ist zwar mehr Aufwand in der Bean aber dafür übersichtlicher und einfacher in der xhtml.

Ich habe folgenden Plan, welchen ich allerdings noch nicht Umgesetzt habe:

Du machst dir in der Bean "Unterlisten" fertig. Die getMethoden bzw. Initmethoden dieser Listen filtern zum Sessionbeginn die Marken heraus.

Grob Dargestellt in Pseudocode wäre das z.B. Sowas

Java:
Lits<autos> alleAutos= Alle Autos; 

List <autos>mercedes= initMercedes();

.....
.....
usw.
.....

public void initMercedes(){

for(int i=0; i< alleAutos.size(); i++){

if(alleAutos.get(i).marke.equals("Mercedes"){
mercedes.add(alleAutos.get(i));
}//ende IF
}//ende For
}//ende Methode

Wenn wir nun die Unterlisten haben, dann sollte sich dein Problem in Luft auflösen:

Code:
<t:selectManyCheckbox id="autos" layout="spread" forceId="true" forceIdIndex="false" value="#{handler.selectedAutos}" required="true">

<f:selectItems value="#{autoHelper.mercedes}" var="mercedes"
				itemLabel="#{auto.shortname}" />
<f:selectItems value="#{autoHelper.vw}" var="vw"
				itemLabel="#{auto.shortname}" />

</t:selectManyCheckbox>

<h:panelGrid columns="2">
			
			<t:dataTable var="row" value="#{autoHelper.mercedes}"
				rowIndexVar="index">
				<h:column>
					<f:facet name="header">
						<t:outputText value="Mercedes" />
					</f:facet>
					<t:checkbox for=":#{form}:mercedes" index="#{index}" />
				</h:column>
			</t:dataTable>

			<t:dataTable var="row" value="#{autoHelper.vw}"
				rowIndexVar="index">
				<h:column>
					<f:facet name="header">
						<t:outputText value="VW" />
					</f:facet>
					<t:checkbox for=":#{form}:vw" index="#{index}" />
				</h:column>
			</t:dataTable>

</h:panelGrid>



HTH

WhiTeY
 
Zuletzt bearbeitet:

gedanke

Mitglied
Hey Mr. WhiTeY,

erst einmal 1000 Dank für deine Mühe!

Aaaaber... ich fürchte, so klappt das nicht. :( Ich hatte auch schon getter für die einzelnen Marken probiert, sodass ich im dataTable dann value="#{autoHelper.getAutos('Mercedes')}" genutzt habe - aber ich kriege im Endeffekt für jede Spalte nur die ersten x Autos gerendert (unabhängig von der Marke). (Die Anzahl stimmt allerdings, also wenn ich z. B. 10 Mercedes und 5 VW habe, dann werden in Mercedes-Spalte 10 Autos und in die VW-Spalte 5 Autos gerendert.) Ich habe ja auch das hier oben bei den selectItems, deswegen wundert es dann irgendwie doch nicht so:

Code:
<f:selectItems value="#{autoHelper.autos}" var="auto"
				itemLabel="#{auto.shortname}" />

Was ich bei deinem Versuch nicht verstehe:

Code:
<f:selectItems value="#{autoHelper.mercedes}" var="mercedes"
				itemLabel="#{auto.shortname}" />
<f:selectItems value="#{autoHelper.vw}" var="vw"
				itemLabel="#{auto.shortname}" />

Was passiert hier mit dem var? Die werden ja nie genutzt. Unten hast du sie dann so verwendet:

Code:
<t:checkbox for=":#{form}:vw" index="#{index}" />

Aber "vw" ist ja keine ID irgendeiner Komponente, weswegen das nicht funktioniert. Füge ich die IDs ein, kriege ich folgendes zu lesen:

Code:
javax.servlet.ServletException: UISelectMany expected

Es sieht so aus, als muss bei

Code:
t:checkbox for=":#{form}:vw"

das "vw" das selectManyCheckbox-Ding sein - und nicht selectItems. Und damit schließt sich der Kreis. :(

Hast du noch eine Idee? Danke! Komisch, wie lange ich mich schon damit aufhalte. Gibt es wirklich keine machbare Lösung?
 

F.S.WhiTeY

Bekanntes Mitglied
Hmm das einzige was mir nun noch übrigbleibt ist dir zu raten das Design komplett zu ändern. Mein Latein mit einfachen lösungen wäre zuende.

Wir könnten zwar noch ein zwei Dinge versuchen mit CSS und Trick zu lösen aber der Erfolg ist nicht garantiert und es macht Arbeit.

Mit Design ändern meine ich nicht nur das Layout, ich würde überlegen die gesammte Programmstrucktur leicht abzuändern.

Das aufteilen der Listen ist eine Variante, eine andere wäre auch die SelectMany aufzuteilen.

Das resultat wäre dann allerdings auch, das du das Atribut handler.selectedAutos aufteilen müsstest und hinterher wieder zusammenführen oder halt mit der Aufteilung weiterarbeiten.

Ich persönlich arbeite wie gesagt nicht mit Prime Faces, daher bleiben mir eventuelle Tricks verborgen. Wenn es eine Möglichkeit gäbe mir Relevante Programmabschnitte zukommen zu lassen würde ich mich bereiterklären da mitzuarbeiten bzw. eine Lösung zu suchen.

Das Problem ist nicht gerade trivial und sollte zu machen sein, nur so atock fällt mir da nix ein.

Aufgeteilte Komponenten sollten halt im Design mit eingeplant werden. Ok, machmal ist weniger mehr und Abstrahieren hat in der OOP-Welt noch keinem geschadet... aber hier würde ich sagen ein VW ist ein VW und ein Audi ein Audi, daher die gehören getrennt. In der Auswahl wie in der Aufführung. Nur eigene Objekte brauchen sie nicht denn es sind alles Autos ;)

Das würde meiner meinung nach einiges einfacher machen auch wenn es im ersten Moment nach wehsentlich mehr arbeit aussieht.

LG

WhiTeY
 

gedanke

Mitglied
Hey WhiTeY!

Das aufteilen der Listen ist eine Variante, eine andere wäre auch die SelectMany aufzuteilen.

Das resultat wäre dann allerdings auch, das du das Atribut handler.selectedAutos aufteilen müsstest und hinterher wieder zusammenführen oder halt mit der Aufteilung weiterarbeiten.

Das ist das einzige, was mir auch noch in den Sinn kommen würde. Auch wenn es erst einmal nicht sehr "sauber" klingt. Aber theoretisch sollte es ja gehen, für jede Marke ein getter/setter und dann in getSelectedAutos die Ergebnisse aller getter zusammenführten. Aber schön ist das irgendwie nicht.

Ich danke für deine Mühe! Ich probiere es morgen mal aus und werde Bescheid geben, ob ich es so hinbekommen habe oder nicht.

Ah, was mir aber einfällt. Ich nutze auch selectOneRadio manchmal als Auswahlkomponente (an Stellen, an denen man nur ein Auto wählen darf). Da vier selectOneRadios hinzurendern ist ja nicht so sinnig. :(
 
Zuletzt bearbeitet:

F.S.WhiTeY

Bekanntes Mitglied
Ah, was mir aber einfällt. Ich nutze auch selectOneRadio manchmal als Auswahlkomponente (an Stellen, an denen man nur ein Auto wählen darf). Da vier selectOneRadios hinzurendern ist ja nicht so sinnig. :(

Nein ist es nicht, da ist es sinniger und schöner ein Menü zu benutzen:

Code:
<h:outputLabel value="*Familienstand:"  styleClass="label"/>
                        <h:selectOneMenu id="FamStand" required="true" value="#{Bean.Antragsteller}" styleClass="input">
                            <f:selectItem itemValue="ledig" itemLabel="ledig"/>
                            <f:selectItem itemValue="verheiratet" itemLabel="verheiratet"/>
                            <f:selectItem itemValue="zusammenlebend" itemLabel="zusammenlebend"/>
                            <f:selectItem itemValue="getrennt" itemLabel="getrennt"/>
                            <f:selectItem itemValue="geschieden" itemLabel="geschieden"/>
                            <f:selectItem itemValue="verwitwet" itemLabel="verwitwet"/>
                        </h:selectOneMenu>

Das kann man auch mit
Code:
selectItems
benutzen und Enums dahinter packen, was schöner ist. Wenn die Enums Properties bekommen kannst du sogar die Booleans "simmulieren" und das ding arbeitet wie radioButtons oder Checkboxen.
 

gedanke

Mitglied
[...] und Enums dahinter packen, was schöner ist. Wenn die Enums Properties bekommen kannst du sogar die Booleans "simmulieren" und das ding arbeitet wie radioButtons oder Checkboxen.

Wie meinst du das? Verstehe ich nicht ganz.

Bei selectManyCheckbox habe ich es jetzt so gelöst, dass ich eine selectManyCheckbox-Komponente pro Marke habe (und die ausgewählten Autos dann in eine Liste zusammenführe, wenn ich sie brauche).

Beim selectOneMenu kann ich aber auch nicht schön "gruppieren", oder?
 

Ähnliche Java Themen


Oben