'How to maintain accordionPanels in the same order?
I'm using accordionPanel in Primefaces. When I refresh the page the order changes! For example: I have 1,2,3 then they become 2,3,1 or 3,2,1 ! The order of the panels changes everytime I refresh the page!
<p:panel toggleable="true" header="Mesure" rendered="#{not empty mesureController.varValues['structure']}">
<p:accordionPanel value="#{mesureController.structureComposants.toArray()}" var="sc">
<p:tab title="#{sc.nomComposant}" closable="false">
<p:dataTable value="#{sc.plans.toArray()}" var="plan" id="plansTable" emptyMessage="">
<p:column headerText="Plan">
<p:outputLabel value="#{plan.nomPlan}"/>
</p:column>
<p:column headerText="Image">
<p:lightBox styleClass="imagebox" id="lighbox1"
rendered="#{not empty plan.image}">
<h:outputLink
value="data:image/png;base64,#{ligneBean.getImageContentsAsBase64(plan)}"
title="#{plan.commentaire}">
<img src="data:image/png;base64,#{ligneBean.getImageContentsAsBase64(plan)}"
style="height: 120px; width: auto; margin-right: 10px;"/>
</h:outputLink>
</p:lightBox>
</p:column>
<p:column headerText="#{mesureController.varValues['typeMesure']}">
<ui:repeat value="#{plan.reperes.toArray()}" var="repere">
<p:panelGrid columns="5" layout="grid">
<p:outputLabel id="nom_repere" value="#{repere.nomRepere}"/>
<p:tooltip id="toolTipGrow" for="nom_repere" value="#{repere.commentaire}"
position="left"/>
<p:outputLabel value="#{repere.repereConfig.temperature.minTemperature}"
title="min temperature"
rendered="#{mesureController.selectedTypeMesure.name().equals('TEMPERATURE')}"/>
<p:outputLabel value="#{repere.repereConfig.epaisseur.minEpaisseur}"
title="min epaisseur"
rendered="#{mesureController.selectedTypeMesure.name().equals('EPAISSEUR')}"/>
<p:inputText value="#{mesureController.currentMesure.structureDetails[repere]}"
disabled="#{not mesureController.firstTask}"
converter="javax.faces.Double" converterMessage="valeur numerique"
style="width: 50px">
<p:ajax event="change" listener="#{mesureController.validateMesureValue}"
update=":iwFormsForm">
</p:ajax>
</p:inputText>
<p:outputLabel value="#{repere.repereConfig.temperature.maxTemperature}"
title="max temperature"
rendered="#{mesureController.selectedTypeMesure.name().equals('TEMPERATURE')}"/>
<p:outputLabel value="#{repere.repereConfig.epaisseur.maxEpaisseur}"
title="max epaisseur"
rendered="#{mesureController.selectedTypeMesure.name().equals('EPAISSEUR')}"/>
</p:panelGrid>
</ui:repeat>
</p:column>
</p:dataTable>
</p:tab>
</p:accordionPanel>
<ui:fragment rendered="#{mesureController.typeStructure.equals('FOUR')}">
<ui:include src="graph.xhtml"/>
</ui:fragment>
<p:accordionPanel value="#{mesureController.fourZones.toArray()}" var="fz" activeIndex="0,1,2,3,4,5">
<p:tab title="#{fz.description}">
<p:dataTable value="#{fz.points.toArray()}" var="fpoint" id="fpointsTable" emptyMessage="" >
<p:column headerText="point">
<p:outputLabel value="#{fpoint.description} #{fpoint.position}(m)"/>
</p:column>
<p:column headerText="#{mesureController.varValues['typeMesure']}">
<p:panelGrid columns="3" layout="grid">
<p:outputLabel value="#{fpoint.temperature.minTemperature}" title="min temperature"
rendered="#{mesureController.selectedTypeMesure.name().equals('TEMPERATURE')}"/>
<p:outputLabel value="#{fpoint.epaisseur.minEpaisseur}" title="min epaisseur"
rendered="#{mesureController.selectedTypeMesure.name().equals('EPAISSEUR')}"/>
<p:inputText value="#{mesureController.currentMesure.fourDetails[fpoint]}"
converter="javax.faces.Double" converterMessage="valeur numerique"
style="width: 50px">
<p:ajax event="change" update=":iwFormsForm"
listener="#{mesureController.validateMesureFourValue}"/>
</p:inputText>
<p:outputLabel value="#{fpoint.temperature.maxTemperature}" title="max temperature"
rendered="#{mesureController.selectedTypeMesure.name().equals('TEMPERATURE')}"/>
<p:outputLabel value="#{fpoint.epaisseur.maxEpaisseur}" title="max epaisseur"
rendered="#{mesureController.selectedTypeMesure.name().equals('EPAISSEUR')}"/>
</p:panelGrid>
</p:column>
</p:dataTable>
</p:tab>
</p:accordionPanel>
<p:accordionPanel value="#{mesureController.tadZones.toArray()}" var="tz">
<p:tab title="#{tz.description}">
<p:dataTable value="#{tz.points.toArray()}" var="tpoint" id="tpointsTable" emptyMessage="">
<p:column headerText="point">
<p:outputLabel value="#{tpoint.description} #{tpoint.position}(m)"/>
</p:column>
<p:column headerText="#{mesureController.varValues['typeMesure']}">
<p:panelGrid columns="3" layout="grid">
<p:outputLabel value="#{tpoint.temperature.minTemperature}" title="min temperature"
rendered="#{mesureController.selectedTypeMesure.name().equals('TEMPERATURE')}"/>
<p:outputLabel value="#{tpoint.epaisseur.minEpaisseur}" title="min epaisseur"
rendered="#{mesureController.selectedTypeMesure.name().equals('EPAISSEUR')}"/>
<p:inputText value="#{mesureController.currentMesure.tadDetails[tpoint]}"
converter="javax.faces.Double" converterMessage="valeur numerique"
style="width: 50px">
<p:ajax event="change" update=":iwFormsForm"
listener="#{mesureController.validateMesureTADValue}"/>
</p:inputText>
<p:outputLabel value="#{tpoint.temperature.maxTemperature}" title="max temperature"
rendered="#{mesureController.selectedTypeMesure.name().equals('TEMPERATURE')}"/>
<p:outputLabel value="#{tpoint.epaisseur.maxEpaisseur}" title="max epaisseur"
rendered="#{mesureController.selectedTypeMesure.name().equals('EPAISSEUR')}"/>
</p:panelGrid>
</p:column>
</p:dataTable>
</p:tab>
</p:accordionPanel>
<p:panel toggleable="true" header="Validation des mesures" rendered="#{mesureController.isValidationMesures()}">
<p:panelGrid id="tmp_validation2" columns="2" class="Wid100">
<h:outputLabel value="Valider les mesure *"/>
<p:selectOneMenu value="#{mesureController.varValues['valider_les_mesures']}" required="true">
<f:selectItem itemLabel="Sélectionner" itemValue="#{null}"/>
<f:selectItem itemLabel="Oui" itemValue="Oui"/>
<f:selectItem itemLabel="Non" itemValue="Non"/>
<p:ajax event="change" process="@this"/>
</p:selectOneMenu>
</p:panelGrid>
</p:panel>
</p:panel>
So I need to know how to fix that, in order to maintain the order of panels in the same way as it is in the html.
Solution 1:[1]
The panels and their 'order' come from
value="#{mesureController.structureComposants.toArray()}"
Which is not PrimeFaces, nor java-ee, nor java but EL (so the tagging is sort of 'wrong'). But effectively the EL is a toArray()
on an a field of an object. So you could (should) create a simple unit test and see what it does in plain java.
Then with 99.999% certainty you'll see the order is 'random' too, making this question a pure java one. Effectivly the order in Set is not guaranteed as it depends on the implementation (an OrderedSet is, others might not be)
So using an OrderedSet
or an (implementation of) Array
directly (e.g. an ArrayList
) will 'fix' this issue
See also
Solution 2:[2]
The panels and their 'order' come from
value="#{mesureController.structureComposants.toArray()}"
Because to fix it, you must create a new property with this value but ordered. For example, if your variable structureComposants is a Set, you could try the following.
List<Entity> structureComposantsList = structureComposants.stream().collect(Collectors.toList());
Collections.sort(structureComposantsList, (o1, o2) -> o1.getAttribute1().compareTo(o2.getAttribute1()));
Note: Change the Entity class for your class and initialize in your @PostContruct method
Finally, use the variable structureComposantsList in your code as
value="#{mesureController.structureComposantsList}"
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | martosfre |