How to get multiple h:selectOneMenu values inside h:dataTable [duplicate] - jsf

This question already has answers here:
Input field in <h:dataTable> always receives value of last item in list
(3 answers)
Closed 7 years ago.
I'm using h selectOneMenu in a datatable and when user press the Set Fixture button i'm saving the value changed in the dropdown, for now i'm using a String variable to get the selected value but the issue is it have the selected value from only the last dropdown. My question is how to get list of all the dropdowns ?
<h:form id="chooseAlmFixtureForm">
<p:panel style="width:80%" header="Set Fixture for Alarms">
<p:dataTable id="tbsetFixtureTable" value="#{setAlmFixtures.alarms}" var="alarmvar" dynamic="false">
<p:column>
<p:commandLink value="View" update=":viewUnknownAlarm" immediate="true" oncomplete="viewDialog.show()">
<f:setPropertyActionListener target="#{currentalarms.viewAlarm}" value="#{alarmvar}"/>
</p:commandLink>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Alarm Time"/>
</f:facet>
<h:outputText value="#{alarmvar.recvTime}"/>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Alarm Type"/>
</f:facet>
<h:outputText value="#{alarmvar.alarmType}"/>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Controller Name"/>
</f:facet>
<h:outputText value="#{alarmvar.controllerName}"/>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Controller Type"/>
</f:facet>
<h:outputText value="#{alarmvar.controllerType}"/>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Choose Fixture"/>
</f:facet>
<h:selectOneMenu id="selectAlarmSite" value="#{setAlmFixtures.selectedFixture}">
<f:selectItems value="#{setAlmFixtures.fixtures}" />
</h:selectOneMenu>
</p:column>
</p:dataTable>
<p:commandButton value="Set Fixtures" actionListener="#{setAlmFixtures.setAlarmsFixtures}" action="#{horizontalmenu.actionCallAlarmsPage}" styleClass="dialogButton"/>
</td><td>
<p:commandButton value="Cancel" actionListener="#{setAlmFixtures.releaseAlarms}" action="#{horizontalmenu.actionCallAlarmsPage}" styleClass="dialogButton"/>
</p:panel>
</h:form>

Currently, your dropdown-value refers to a single variable in your bean (which seems to be selectedFixture of class SetAlmFixtures). How would a single variable represent a state (value) for multiple row (here: alarms)?
You need to link the selected value to the row (alarm) it refers to. To do so, you have several options, two approaches following:
Use the variable of your alarm-object, just the same way as you used them as outputvalues inside the other columns. This way, the alarm's fixture is set directly on value (form) processing. Currently, both of your buttons submit the form (type="submit" is default), depending on what your actionlisteners do, you might consider changing the Cancel-button's type to button.
Map the fixtures and alarms. You could use something like Map<Long, Fixture> fixturemap; mapping alarm-id's to their selected fixture, assuming all alarms have a non-null id. The map's value can be referred by setAlmFixtures.fixturemap['alarmvar.id']. Make sure you provide a getter for the map and the id. Also, you need to initialize the map with the initial fixture values for each alarm.

Related

How to block a single datatable cell in primefaces with blockUI

I'm creating a datatable with some some dynamically generated columns. In each of the cells of those columns, there's a button to refresh the data of that specific cell.
What I want is that the cell is blocked when the button on that cell is pressed.
Sample code:
<p:dataTable id="table" var="tableVar" value="#{tableValues}">
<p:columns id="column" var="columnVar" value="#{columnValues}">
<f:facet name="header">
<h:outputText value ="#{columnVar}"/>
</f:facet>
<h:outputText value="Some Text"/>
<p:commandButton value="Button Text"
id="button"
update="table"
actionListener="#{some.method()}"/>
<p:blockUI block="?????" trigger="button">
<p:graphicImage name="loading.gif"/>
</p:blockUI>
</p:columns>
</p:dataTable>
I don't know what should go in the block parameter to only block a cell. I also tried to just block="column", but even that wasn't blocking the column as I expected, instead it was just displaying the loading gif near the button but not blocking anything.
I have seen this question How update just specific cell in primefaces dataTable where the answers say it's not possible to specify a single cell, but it's from 2012, and the answers mention that it might get fixed on a later version.
After playing a bit, I found a solution.
You can define a <p:outputpanel id="cell"></p:outputpanel> surrounding the content of the cell, and then block it with block="cell" in the blockUI component.
The result would be something like:
<p:dataTable id="table" var="tableVar" value="#{tableValues}">
<p:columns id="column" var="columnVar" value="#{columnValues}">
<f:facet name="header">
<h:outputText value ="#{columnVar}"/>
</f:facet>
<p:outputpanel id="cell">
<h:outputText value="Some Text"/>
<p:commandButton value="Button Text"
id="button"
update="table"
actionListener="#{some.method()}"/>
<p:blockUI block="cell" trigger="button">
<p:graphicImage name="loading.gif"/>
</p:blockUI>
</p:outputpanel>
</p:columns>
</p:dataTable>

Submit in a fetch mode collapsed rows

I have this datatable:
<p:dataTable id="necesidades"
value="#{registrarAccionDosBean.accionDos.necesidadesConTema}"
rendered="#{not empty registrarAccionDosBean.accionDos.necesidadesConTema}"
var="necesidad"
rowKey="#{necesidad.idNecesidad}">
<p:column style="width:16px">
<p:rowToggler />
</p:column>
<p:rowExpansion>
<h:panelGroup id="grupoTema">
<h:panelGroup id="edicion" rendered="#{necesidad.tema.idTema ne null}">
<p:row>
<p:column >
<h:outputLabel value="#{etiq.lbl_comunes_requerido} #{etiq.etiqueta_checkbox_transparenciasFocalizadas}" styleClass="textoAcciones"/>
</p:column>
<p:column >
<!-- Nested data table -->
<p:dataTable id="transparenciasInplace"
var="transparencias"
value="#{registrarAccionDosBean.transparenciasFocalizadas}"
selection="#{necesidad.tema.transparenciasFocalizadas}"
rowKey="#{transparencias.idTf}">
<f:facet name="header">
Objetives
</f:facet>
<p:column selectionMode="multiple" style="width:16px;text-align:center"/>
<p:column>
<h:outputLabel value="#{transparencias.descripcion}" styleClass="textoAccionesSmall"/>
</p:column>
</p:dataTable>
</p:column>
</p:row>
</h:panelGroup>
</h:panelGroup>
</p:rowExpansion>
</p:dataTable>
I have n rows collapsed with information inside of each of them, this information was persisted in different times and days, so I need to save some information plus the n rows as a whole, the problem is that the rows are collapsed when is show on screen and I want to be in that way because a can have a lot rows on screen and if I show them expanded it will be hard to read, but when I send it through a command button the table inside my collapsed row are setting null, I need to expand each of them in order to properly send all the information.
So I want to send the information collapsed but in some way force to fetch the information inside of each of them
I am getting the information from the database right, because there I just fetch my query and get the information right, so my problem is on my jsf page I think

update datatable footer primefaces (facet or columnGroup)

I want to make a footer in dataTable and I need to update when the values inside the DT changes.
The problem is that ajax update simply don't occurs.
I've tried two ways:
<p:dataTable
id="dataTableAvaliacao" var="aluno"
value="#{alunoAvaliacaoMB.alunos}">
<p:column>
<p:inputText id="inputNota"
value="#{aluno.getNota(avaliacao.property).vlNotaString}">
<p:ajax event="change"
update=":form:dataTableAvaliacao:mediaAluno, :form:dataTableAvaliacao:mediaAvaliacao" />
</p:inputText>
</p:column>
<p:columnGroup type="footer" id="mediaAvaliacao">
<p:row>
<p:column
footerText="Nota média da avaliação" />
</p:row>
<p:row>
<ui:repeat value="#{alunoAvaliacaoMB.colunasAvaliacoes}"
var="avaliacao">
<p:column id="colunaMedia"
footerText="#{alunoAvaliacaoMB.getMediaAvaliacao(avaliacao.property)}"/>
</ui:repeat>
</p:row>
</p:columnGroup>
<p:dataTable>
The update doesn't occurs...
second way (based on this answer on SO: How to ajax update an item in the footer of a PrimeFaces dataTable?):
<p:remoteCommand name="refreshFooter" update=":form:dataTableAvaliacao:outputMediaAvaliacao"/>
<p:dataTable
id="dataTableAvaliacao" var="aluno"
value="#{alunoAvaliacaoMB.alunos}">
<p:column>
<p:inputText id="inputNota"
value="#{aluno.getNota(avaliacao.property).vlNotaString}">
<p:ajax event="change"
update=":form:dataTableAvaliacao:mediaAluno" oncomplete="refreshFooter();" />
</p:inputText>
</p:column>
<p:dataTable>
<f:facet name="footer">
<h:outputText colspan="1" value="Nota média da avaliação:"/>
<ui:repeat value="#{alunoAvaliacaoMB.colunasAvaliacoes}"
var="avaliacao">
<h:outputText id="outputMediaAvaliacao"
value="#{alunoAvaliacaoMB.getMediaAvaliacao(avaliacao.property)}"
</ui:repeat>
</f:facet>
I've also tried
<p:remoteCommand name="refreshFooter" update=":form:outputMediaAvaliacao"/>
If I put
<p:ajax event="change"
update=":form:dataTableAvaliacao:mediaAluno, :form:dataTableAvaliacao" />
in the first way, it works, but I don't wanna update all dataTable every time.
What I'm doing wrong? is it a bug?
Referring on 2nd way from your question that you based on this answer...
actually it is possible to update p:dataTable footer (even from within table itself)...but with one modification of your code.
Reason why your implementation does not work is that you did not take into account that <h:outputText id="outputMediaAvaliacao"../> is wrapped with ui:repeat.
In that case, p:remoteCommand is not able to find h:outputText component ID defined in update attribute because that ID does not exist in DOM:
ui:repeat is actually copying h:outputText as many times as list from value attribute is long and appending all parent IDs to newly created native HTML components
<span id="form:dataTableAvaliacao:avaliacao:0:outputMediaAvaliacao">...</span>
<span id="form:dataTableAvaliacao:avaliacao:1:outputMediaAvaliacao">...</span>
<span id="form:dataTableAvaliacao:avaliacao:2:outputMediaAvaliacao">...</span>
...
(you can see the same using DOM inspector of your favorite browser)
SOLUTION
After you learn and understand all facts stated above (like I did :) ), solution is quite simple:
wrap ui:repeat with some parent element and assign ID to parent element. For example like this
<f:facet name="footer">
<h:outputText value="Nota média da avaliação:"/>
<h:panelGroup id="footerPanel">
<ui:repeat value="#{alunoAvaliacaoMB.colunasAvaliacoes}"
var="avaliacao" id="avaliacao">
<h:outputText id="outputMediaAvaliacao" value="#{alunoAvaliacaoMB.getMediaAvaliacao(avaliacao.property)}" />
</ui:repeat>
</h:panelGroup>
</f:facet>
and modify p:ajax of p:inputText to update newly created element after text is changed
<p:ajax event="change" update=":form:dataTableAvaliacao:footerPanel" />
On this way all children elements of h:panelGroup will be updated (meaning only footer will be updated and not entire table).
And now, after you solved updating, you can focus on designing of all UI elements under h:panelGroup to make them fit your requirements.

SelectOneMenu in Datatable with empty SelectItem

When I use an empty SelectItem in a SelectOneMenu to provide my users with an empty choice in the SelectOneMenu it works fine. As was suggested in this thread: Best way to add a "nothing selected" option to a selectOneMenu in JSF
But when I use an empty SelectItem in a SelectOneMenu which resides in a datable it does not persist the correct SelectItem when I use CellEditing in the data table.
Here is my code:
<p:dataTable id="fooTable"
value="#{fooSessionBean.foos}"
var="foo"
rows="15"
style="width: 100%"
paginator="true"
paginatorPosition="bottom"
paginatorAlwaysVisible="false"
editable="true" >
...
<p:column sortBy="#{empty foo.bar ? '' : foo.bar.name}">
<p:cellEditor>
<f:facet name="output"> <h:outputText value="#{foo.bar.name}" title="#{foo.bar.name}" rendered="#{!empty foo.bar}" /></f:facet>
<f:facet name="input">
<p:selectOneMenu id="bars" value="#{foo.bar}" converter="foobarConverter" style="width:100%">
<f:selectItem itemLabel="No bar" itemValue="#{null}" noSelectionOption="true" />
<f:selectItems value="#{fooSessionBean.foos}" var="bars" itemLabel="#{bars.name}" itemValue="#{bars}" />
</p:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
...
<p:column style="width:10%">
<p:rowEditor />
<p:commandButton action="#{fooSessionBean.delete(foo.id)}" icon="ui-icon-trash" title="remove" ajax="false"/>
</p:column>
A Foo object has a field Bar. The code above generates a list of Bar items when you try to edit the field using RowEditing. It is also possible for the Foo object to have no Bar field. Hence the empty SelectItem.
This all works except that the wrong Bar item is persisted in Foo object. The Bar object before the one I have selected is persisted. eg:
The SelectOneMenu contains:
emptybar
bar1
bar2
bar3
When you select bar2, bar1 will be persisted in te foo object.
Is it possible to use the different components in such a away or am I overlooking something else? Because I have found little references of people attempting this and having the same problem I am having.

How can I make p:cellEditor conditional in PrimeFaces?

Here is my code that doesn't work:
...
<p:column sortBy="#{invoice.customerId}" id="customerId">
<f:facet name="header"><h:outputText value="Customer ID"/></f:facet>
<f:facet name="output" rendered="#{!editUIBean.isEditable('customerId')}">
<h:outputText value="#{invoice.customerId}"/>
</f:facet>
<p:cellEditor rendered="#{editUIBean.isEditable('customerId')}">
<f:facet name="output">
<h:outputText value="#{invoice.customerId}"/>
</f:facet>
<f:facet name="input">
<h:inputText value="#{invoice.customerId}"/>
</f:facet>
</p:cellEditor>
</p:column>
...
So what I am trying to do: The user picks an option, that option determines which records are editable and only displays the records that are editable for that option. For any given option, only certain columns within those records are editable. The isEditable(columnName) method returns true if for given option the column is editable or false if it is not editable. What I want to do is, when the user clicks edit for the record, the editable fields display input fields and then non-editable fields display their values. With the code above, when the column isn't editable, the value doesn't display, before and after clicking edit. When the field is editable, the value displays, and when you click edit, the value is replaced with an input field containing the value. So my example works except that the value is completely hidden when the field is not editable. I want the non-editable values to be displayed when not editing and when editing, I just don't want them to be editable during edit.
This,
<p:column>
<f:facet name="output" rendered="#{!editUIBean.isEditable('customerId')}">
<h:outputText value="#{invoice.customerId}" />
</f:facet>
...
</p:column>
is not right. The <p:column> doesn't support a <f:facet name="output">. Just put the rendered condition on the <h:outputText> itself.
<p:column>
<h:outputText value="#{invoice.customerId}" rendered="#{!editUIBean.isEditable('customerId')}" />
...
</p:column>

Resources