h:selectOneMenu in loop - jsf

I want to remember values from multiple h:selectOneMenu component in c:forEach loop. Now only last value from h:selectOneMenu is remember. I don't know how many h:selectOneMenu will appear.
<h:panelGrid
id="wynik"
columns="2"
border="0"
cellpadding="2"
cellspacing="0"
rowClasses="jsfcrud_odd_row,jsfcrud_even_row"
rules="all"
style="border:solid 1px">
<h:outputText id="ns" value="Numer stanowiska"/>
<h:outputText id="kontr" value="Kontroler"/>
<c:forEach
var="stanowisko"
begin="1"
end="#{stojakiController.selected.iloscstanowisk}"
step="1">
<h:column>
<h:outputText value="#{stanowisko}"/>
</h:column>
<h:column>
<h:selectOneMenu
id="kontroler_#{stanowisko}"
value="#{wyposazenieStojakaController.selected.kontroler}"
title="#{bundle.CreateWyposazenieStojakaTitle_kontroler}"
required="true"
requiredMessage="#{bundle.CreateWyposazenieStojakaRequiredMessage_kontroler}">
<f:selectItems value="#{kontroleryController.itemsAvailableSelectOne}"/>
</h:selectOneMenu>
</h:column>
</c:forEach>
</h:panelGrid>

This is not the right way to render a table based on a dynamically sized collection. You're binding the value of each row to one and same backing bean property. This property would get overwritten every time whenever each row needs to set the value. That's why you end up with only the value of the last row.
You should be using <h:dataTable> instead, not a <h:panelGrid> with a <c:forEach>. You should be preparing a collection of concrete model objects, not only the size of objects. For example,
public class Item {
private String value;
// ...
}
Then, in the (post)constructor of the backing bean you should prepare as many as necessary.
public class Bean {
private List<Item> items;
#PostConstruct
public void init() {
items = new ArrayList<Item>();
for (int i = 0; i < yourDesiredAmountOfItems; i++) {
items.add(new Item());
}
}
// ...
}
And here's a basic kickoff example how you should use it:
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:selectOneMenu value="#{item.value}">
<f:selectItems value="#{bean.availableValues}" />
</h:selectOneMenu>
</h:column>
</h:dataTable>
When you submit the form, JSF will set the value of each row rightly in each separate item object associated with the row.

Related

How to bind List of List in jsf datatable

Hi I have a variable like
List<List<MyObject>> x = new ArrayList<List<MyObject>>();
I wanted this bind to a datatable in jsf which contains select
<datatable>
<column>
<Select/>
</column>
</datatable>
Is this possible in jsf
Code:
view.xhtml
<h:dataTable id="i1" value="#{bean.listoflist}" var="list1">
<h:column>
<h:selectOneListbox value="#{bean.somestring}" >
<f:selectItems value="#{list1.?}" var="any" itemValue="#{any.??}/>"
</h:selectOneListbox>
</h:column>
</h:dataTable>`
Bean.java (name = "bean")
public class Bean implements Serializable
{
List<List<MyObject>> listoflist = new ArrayList<List<MyObject>>()
//--------------Getters and Setter
}
MyObject.java
public class MyObject
{
private String s1;
private String s2;
//---------------getter and setter
}
If I understood your problem properly, you want to make a datatable of select elements whose options come form the nested list of your model. If yes, here is the solution:
prepare an array of selected elements per the size of the outer list;
have a converter for your model object;
fill the UI components accordingly.
Below you may find a working example:
<h:dataTable value="#{bean.listOfLists}" var="list" binding="#{table}" >
<h:column>
<h:selectOneListbox value="#{bean.selection[table.rowIndex]}" converter="myObjectConverter" >
<f:selectItems value="#{list}" var="obj" itemValue="#{obj}" itemLabel="#{obj.s1}" />
</h:selectOneListbox>
</h:column>
</h:dataTable>
with
MyObject[] selection = new MyObject[listOfLists.size()];

Get rowIndex of rich:dataTable rows

In my JSF application, I use a rich:dataTable as follows:
<rich:dataTable id="itemTable" value="#{backingBean.itemsList}" var="i" >
<rich:column> <f:facet name="header">ItemValue</f:facet>
<h:inputText id="myId" value="#{i.value}" style="width: 30px" />
</rich:column> </rich:dataTable>
<h:commandButton id="saveB" value="Save" action="#{backingBean.doSave()}" />
Bean code of doSave:
public String doSave() {
Iterator<Item> = itemsList.iterator();
while(iter.hasNext()) {
//do something
}
}
In the doSave()-Method, i need to know the row index of the current Item, is there a way to achieve this?
While Richfaces extended data tables support a selection management, Richfaces datatables don't.
What I found the easiest way to do to retrieve a somehow selected item from a list, is to add an icon to every row. For this, put the command-Button into the data table itself:
<rich:dataTable id="itemTable" value="#{backingBean.itemsList}" var="i" >
<rich:column>
<h:inputText id="myId" value="#{i.value}" />
<h:commandButton id="saveB" action="#{backingBean.doSave}" />
</rich:column>
</rich:dataTable>
In the bean code, provide the method doSave but with an additional parameter ´ActionEvent´
public String doSave(ActionEvent ev) {
Item selectedItem = null;
UIDataTable objHtmlDataTable = retrieveDataTable((UIComponent)ev.getSource());
if (objHtmlDataTable != null) {
selectedItem = (Item) objHtmlDataTable.getRowData();
}
}
private static UIDataTable retrieveDataTable(UIComponent component) {
if (component instanceof UIDataTable) {return (UIDataTable) component;}
if (component.getParent() == null) {return null;}
return retrieveDataTable(component.getParent());
}
You see, that the ActionEvent ev provides you with the source element (UIComponent)ev.getSource(). Traverse through it until you hit the UIDataTable element and use it's row data.
Possible way two is to justgive the element as parameter with the function call:
<rich:dataTable id="itemTable" value="#{backingBean.itemsList}" var="i" >
<rich:column>
<h:inputText id="myId" value="#{i.value}" />
<h:commandButton id="saveB" action="#{backingBean.doSave(i)}" />
</rich:column>
</rich:dataTable>
and in the bean
public String doSave(Item item) {
// do stuff
}
That's not as clean, but should work with the EL, too. Hope, it helps...

JSF Cannot save change to datatable row to the database

I have a primefaces datatable. I populate it from the database. One of the fields is a boolean represented by a checkbox. I want that if I check or uncheck the checkbox, that I can save the change back to the database.
I have tried passing the current value of the row to the managed bean to save, but the new value of the checkbox isn't reflected in the current row object. How can I get the change into the current row object so I can successfully save the change to the DB?
Here is what I am doing now... I have tried to provide just what is needed. If it is too much information or too little, let me know. Thanks.
#ManagedBean(name = "itemManagerBean")
#ViewScoped
public class ItemManagerBean implements Serializable {
...
public ArrayList<Item> getAllItemsForUser() {
List list = ecf.findByPartyId(user.getPartyId());
ArrayList<Item> itemList = new ArrayList<>(list);
return (itemList);
}
...
public String saveItem(Item item){
System.out.println(item.toString());
ecf.updateRecord(item);
return (null);
}
}
//item class
public class Item {
private BigInteger itemId;
private String name;
priave boolean saleable; //database column is not null
//getters and setters
}
//facelet
<h:form>
<p:dataTable id="id_itemList"
var="item"
value="#{itemManagerBean.allItemsForUser}" >
<p:column headerText="ID">
<h:outputText value="#{item.itemId}" />
</p:column>
<p:column headerText="Name">
<h:outputText value="#{item.name}" />
</p:column>
<p:column headerText="Saleable" >
<p:selectBooleanCheckbox value="#{item.saleable}" />
</p:column>
<p:column width="15" >
<p:commandButton id="id_saveRowButton" icon="ui-icon-disk"
title="Save" action="#{itemManagerBean.saveItem(item)}"/>
</p:column>
</p:dataTable>
</h:form>
You need to create a selectedItem property in ItemManagerBean and update its value when the user clicks on the commandButton:
In ItemManagerBean
private Item selectedItem;
// getter and setter
In the xhtml page
<p:column width="15" >
<p:commandButton id="id_saveRowButton" icon="ui-icon-disk"
title="Save" action="#{itemManagerBean.saveItem}">
<f:setPropertyActionListener value="#{item}" target="#{itemManagerBean.selectedItem}" />
</p:commandButton>
</p:column>
(Note that you don't need to pass item through saveItem method. Modify saveItem in the managed bean in order to make it work with selectedItem instead of accepting an input item).
Links:
example in the PrimeFaces showcase
Passing parameter to JSF action
BalusC blog

JSF datatable: adding and removing rows clear rows values

I have a h:datatable showing a list of rows, and the fields of each row are input fields.
I render an "Add Row" button before the table, and a "Remove Row" button on each row of the table.
The baking bean is viewScoped, and the buttons add/remove elements from the java list in the backing bean, and then return to the same view.
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
Everything works ok but one thing: the values of the input fileds are cleared. I thought that the view kept the values beacuse the bean is viewScoped.
How can I achieve adding/removing rows without triggering validations and keeping the values that were already typed by the user in the form?
My view:
<h:form>
<h:commandButton value="Añadir Fila" immediate="true" action="#{tablaController.addRowAction}" />
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" immediate="true" action="#{tablaController.removeRowAction(fila)}" />
</h:column>
</h:dataTable>
</h:form>
My backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
boolean exito = this.lista.remove(f);
return "";
}
...
}
UPDATE --> MY SOLUTION:
I write here my solution if someone is interested.
The problem is that I use immediate="true" to skip validations, but this makes to skip the update_model_values too, so that the values entered by the user in the form are lost after clicking the add/remove buttons and re-redenring the page.
As I use "JSR-303 bean validation", my solution was to skip validations using the f:validateBean to enable/disable them. Depending on the button I click, if I want the validations to execute, I enable the bean validation (for example in a "submit" button), and if I want to skip them, I disable bean validation (like in the add/remove row buttons). But anyway the update_model_values always executes, so the values are not lost.
Here's the view:
<h:form>
<f:validateBean disabled="#{!empty param['disableValidation']}">
<h:commandButton value="Añadir Fila" action="#{tablaController.addRowAction}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" action="#{tablaController.removeRowAction(fila)}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Submit" action="#{tablaController.saveData}" />
</f:validateBean>
</h:form>
The backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("fila "+i);
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
this.lista.remove(f);
return "";
}
...
public String saveData () {
...
//processes the valid data
//for example, calls to a service method to store them in a database
...
return "";
}
...
}
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
immediate="true" is the wrong tool for the job. It should be used to prioritize validation, not to enable/disable validation. The difference is rather huge as you encountered yourself.
You want to trigger validation conditionally. In case of e.g. required="true" that'd be as easy as
<h:inputText ... required="#{saveButtonPressed}" />
where #{saveButtonPressed} evaluates true when the save button is pressed. E.g. when its client ID is present in request parameter map.
In case of JSR 303 bean validation, that'd be a matter of
<f:validateBean disabled="#{not saveButtonPressed}">
<h:inputText ... />
</f:validateBean>
or with OmniFaces <o:validateBean> which allows controlling that on a per-command basis.
<h:commandButton id="add" ...>
<o:validateBean disabled="true" />
</h:commandButton>
I had exactly the same problem. In short, you can NOT use immediate for action that update data table(UIData) or facelet repeat. Short explanation:submitted values are not kept for re-display if inputs in UIData do not go through validation. Long explanation can be found here: long explanation and a related bug in Mojarra

JSF commandbutton id inside datatable

How can I add in commandbutton inside datatable?
<hx:dataTableEx value="#{searchData.searchFriends}" var="s">
<hx:columnEx>
<f:facet name="header">
<h:outputText value="First Name" />
</f:facet>
<hx:requestLink action="#{pc_Search.doAddFriendAction}">
<h:outputText value="Add as Friend" />
<f:param name="friendId" value="#{s.memberId}" />
</hx:requestLink>
</hx:columnEx>
</hx:dataTableEx>
To get the data at backend
String friendId = (String)getRequestParam().get("friendId");
But once I change the requestlink to command button the friedId = null? any idea how can i pass value using command button
Wrap the datatable value in a DataModel. Then you can obtain the selected row by DataModel#getRowData().
public class Bean {
private List<Friend> friends;
private DataModel friendsModel;
public Bean () {
friends = getItSomehow();
friendsModel = new ListDataModel(friends);
}
public void addAsFriend() {
Friend selectedFriend = (Friend) friendsModel.getRowData();
// ...
}
}
with
<h:dataTable value="#{bean.friendsModel}" var="friend">
<h:column>
<h:commandButton value="Add as friend" action="#{bean.addAsFriend}" />
</h:column>
</h:dataTable>
Should work as good with IBM Faces Client Framework (those hx: components).

Resources