I'm developing a webshop and I'm facing problems with getting input values from JSF components in the backing bean. I have a datatable, which dynamically loads records from a database table. I want the user to be able to select the amount of items they want to buy and click a button to add them to their shoppingcart. I'm using a dropdownbox to allow the user to select a value, but no matter what value is selected, the value I get in my backing bean is always 1. Any help would be greatly appreciated.
Here's the code for the jsf page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="/WEB-INF/templates/basictemplate.xhtml">
<ui:define name="content">
<h:form id="form">
<p:dataTable var="necklace" value="#{necklaceBean.necklaces}" paginator="true" rows="10" id="necklaceTable" binding="#{necklaceBean.dataTableNecklaces }"
paginatorTemplate="{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}">
<f:facet name="header">
Kettingen
</f:facet>
<p:column headerText="Foto" id="picture">
<p:lightBox styleClass="imagebox">
<h:outputLink value="#{necklace.picture }" title="#{necklace.productId }">
<h:graphicImage url="#{necklace.picture }" width="175" height="116"/>
</h:outputLink>
</p:lightBox>
</p:column>
<p:column headerText="Omschrijving" id="description">
<p>
#{necklace.description}
</p>
<p>
Prijs: #{necklace.price} Euro
</p>
<p>
<p:selectOneMenu value="#{necklaceBean.amount}">
<f:selectItem itemLabel="1" itemValue="1" />
<f:selectItem itemLabel="2" itemValue="2" />
<f:selectItem itemLabel="3" itemValue="3" />
<f:selectItem itemLabel="4" itemValue="4" />
<f:selectItem itemLabel="5" itemValue="5" />
<f:selectItem itemLabel="6" itemValue="6" />
<f:selectItem itemLabel="7" itemValue="7" />
<f:selectItem itemLabel="8" itemValue="8" />
<f:selectItem itemLabel="9" itemValue="9" />
<f:selectItem itemLabel="10" itemValue="10" />
</p:selectOneMenu>
X
<p:commandButton value="Toevoegen aan winkelwagentje" action="#{necklaceBean.addNecklaceToShoppingCart}"
disabled="#{necklace.soldOut}" ajax="false" />
</p>
</p:column>
</p:dataTable>
</h:form>
</ui:define>
</ui:composition>
</html>
And here's the backing bean:
import java.util.List;
import org.primefaces.component.datatable.DataTable;
import be.petitefolie.site.controller.controllerobjects.Product;
import be.petitefolie.site.controller.controllerobjects.ProductType;
public class NecklaceBean extends ProductBean {
private List<Product> necklaces;
private int amount;
private DataTable dataTableNecklaces;
public NecklaceBean(){
necklaces = super.listProductsByPoductType(ProductType.NECKLACE);
}
public List<Product> getNecklaces() {
return necklaces;
}
public void setNecklaces(List<Product> necklaces) {
this.necklaces = necklaces;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public DataTable getDataTableNecklaces() {
return dataTableNecklaces;
}
public void setDataTableNecklaces(DataTable dataTableNecklaces) {
this.dataTableNecklaces = dataTableNecklaces;
}
public String addNecklaceToShoppingCart(){
super.addProductToShoppingCart((Product)this.dataTableNecklaces.getRowData(), amount);
return null;
}
}
The problem is that you are binding a single bean to the components of each row in your table.
If you have multiple rows and in the first one you select 3 in the dropdown box and press "add to shopping cart", then if there is another row with 1 selected in the dropdown box, the bean will get updated to 1 (prcisely: firstly it will get updated according to the first row to 3, then according to the second row to 1, and so on).
I believe that this is the source of your problems.
One solution would be to create an object like:
class ProductPurchase{
Necklace necklace;
int amount;
}
change the List<Product> to List<ProductPurchase>, bind the drop down list value to necklace.amount and set the action of "add to cart" to action="#{necklaceBean.addToShoppingCart(necklace)".
Related
This question already has answers here:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
(5 answers)
Closed 6 years ago.
I have an selectOneMenu and when Its value at 0, I want to "Add" button does not show up. I have rendered for this situation. Here is code ;
<p:panelGrid id="pnlRegister" columns="6" style="width: 95%" >
<p:inputText id="name" class=" width100" value="#{register.name}" />
<p:selectOneMenu id="numberOfChild" value="#{register.numberOfChild}" >
<p:ajax listener="#{register.listenNumberOfChild()}" update="pnlRegister" />
<f:selectItem itemValue="0" itemLabel="0" />
<f:selectItem itemValue="1" itemLabel="1" />
<f:selectItem itemValue="2" itemLabel="2" />
<f:selectItem itemValue="3" itemLabel="3" />
<f:selectItem itemValue="4" itemLabel="4" />
<f:selectItem itemValue="5" itemLabel="5" />
</p:selectOneMenu>
<p:commandButton id="addPerson" value="Add" actionListener="#{register.openPersonDialog(1)}" rendered="#{register.visibleAddPersonButton}" >
<p:ajax event="dialogReturn" update="pnlPerson" />
</p:commandButton>
And Bean code;
public void listenNumberOfChild() {
if (numberOfChild == 0) {
visibleAddPersonButton = false;
} else {
visibleAddPersonButton = true;
}
System.out.println("ListenerNumberOfChild " + numberOfChild);
}
</panelGrid>
Now problem is, when I change numberOfChild, listener works uptades pnlRegister as expected. However server does not keep inputText values. For example before listener works, I write register.name as "John". After listener works, it does not keep it and it gets as null. I hope I could tell what I'm trying and what is problem. So do you have any suggestion ? Also I tried RequestContext.getCurrentInstance().update but same problem occured.
This is how I made it work:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<f:view>
<h:head>
<title>pfaces</title>
</h:head>
<h:form>
<p:panelGrid id="pnlRegister" columns="3" style="width: 95%">
<p:inputText id="name" value="#{register.name}"/>
<p:selectOneMenu id="numberOfChild" value="#{register.numberOfChild}">
<p:ajax process="name numberOfChild"
listener="#{register.listenNumberOfChild()}" update="pnlRegister"/>
<f:selectItem itemValue="0" itemLabel="0"/>
<f:selectItem itemValue="1" itemLabel="1"/>
<f:selectItem itemValue="2" itemLabel="2"/>
</p:selectOneMenu>
<p:commandButton id="addPerson" value="Add"
rendered="#{register.visibleAddPersonButton}"/>
</p:panelGrid>
</h:form>
<h:body>
</h:body>
</f:view>
</html>
and the backing bean:
package biz.tugay.jsfexampla;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class Register {
private boolean visibleAddPersonButton = false;
private int numberOfChild = 0;
private String name;
public boolean isVisibleAddPersonButton() {
return visibleAddPersonButton;
}
public void setVisibleAddPersonButton(boolean visibleAddPersonButton) {
this.visibleAddPersonButton = visibleAddPersonButton;
}
public int getNumberOfChild() {
return numberOfChild;
}
public void setNumberOfChild(int numberOfChild) {
this.numberOfChild = numberOfChild;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void listenNumberOfChild() {
visibleAddPersonButton = numberOfChild != 0;
System.out.println("ListenerNumberOfChild " + numberOfChild);
}
}
Here, you can see it in action: https://youtu.be/IQN3HAejhcM
I am trying to display all available FontAwesome icons in a p:selectOneMenu component.
The renderer is supposed to render the icon first, then display the icon's name. A similar example can be found here but is implemented especially for BootStrap: https://mjolnic.com/fontawesome-iconpicker/
----------------------------------
|- ICON - | Icon name |
----------------------------------
Unfortunately, the custom columns just do not get rendered. The p:selectOneMenuappears but is rendered as by default.
My picker xhtml page looks as follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<body>
<p:panel>
<h:form id="iconPicker">
<p:selectOneMenu id="iconSelectOneMenu"
value="#{iconController.availableIconStrings}">
<f:selectItem itemLabel="Choose icon"
noSelectionOption="true" />
<f:selectItems
value="#{categoryController.availableIconStrings}"
var="_icon" itemValue="#{_icon}"
itemLabel="#{_icon}" />
<p:column>
<p:button id="iconButton" icon="#{_icon}" />
</p:column>
<p:column>
<h:outputText value="#{_icon}" />
</p:column>
</p:selectOneMenu>
</h:form>
</p:panel>
</body>
</html>
The IconController class:
public class IconController implements Serializable {
private List<String> availableIconStrings;
public IconController() { }
#PostConstruct
public void init() {
availableIconStrings = new ArrayList<>();
availableIconStrings.addAll(Arrays
.asList("fa-adjust,fa-adn,fa-align-center,fa-align-justify,fa-align-left,"
+ "fa-align-right,fa-ambulance,fa-anchor,fa-android,fa-angellist,"
+ "fa-angle-double-down,fa-angle-double-left,fa-angle-double-right,"
+ "fa-angle-double-up,fa-angle-down,fa-angle-left,fa-angle-right"
// Shortened list
.split(",")));
}
public List<String> getAvailableIconStrings() {
return availableIconStrings;
}
public void setAvailableIconStrings(List<String> availableIconStrings) {
this.availableIconStrings = availableIconStrings;
}
}
As you can see, I am trying to render the icon using a p:button. Do I understand it correctly that I need a PrimeFaces component that is able to display icons (e.g. p:button, p:commandButton, p:commandLink) to achieve my goal?
Any help is appreciated. Thanks a lot.
P.S.: Using PrimeFaces 5.3, JSF 2.2 and Mojarra on WildFly 9.0.2
For simplicity and re-usability, I decided to wrap the Strings in an Icon class and not to follow implement a different Renderer class as suggested by BalusC in the workaround (https://stackoverflow.com/a/32740430/2118909).
public class Icon {
private String fontIconName;
public Icon(String fontIconName) {
this.fontIconName = fontIconName;
}
public String getFontIconName() {
return fontIconName;
}
public void setFontIconName(String fontIconName) {
this.fontIconName = fontIconName;
}
}
The JSF page looks as follows:
<p:selectOneMenu id="iconSelectOneMenu"
value="#{iconController.selectedIcon}" var="_icon" converter="#{iconConverter}">
<f:selectItem itemLabel="Choose icon"
noSelectionOption="true" />
<f:selectItems
value="#{categoryController.availableIcons}" itemValue="#{_icon}"
itemLabel="#{_icon.fontIconName}" />
<p:column>
<i class="fa fa-fw #{_icon.fontIconName}"/>
</p:column>
<p:column>
<h:outputText value="#{_icon.fontIconName}" />
</p:column>
</p:selectOneMenu>
Please also note the following:
#{iconController.selectedIcon} now refers to an instance of the Icon class
#{iconController.availableIcons} now refers to a List<Icon> instance
I have added a Converter for the Icon class.
The icon is now rendered in an <i/> element.
Please also note the importance and role of the customContent variable in the SelectOneMenuRenderer.encodePanel(...) method which indicates that you need a var value on the p:selectOneMenu directly (not in the <f:selectItems/> element!) or the renderer will not recognize that there is custom content as it does not evaluate the <f:selectItems/> var attribute.
Two things:
In order to use p:column in combination with p:selectOneMenu you need to declare the var attribute on the p:selectOneMenu and reference it within your p:column. An example can be found on the PrimeFaces showcase.
So your code should be:
<p:selectOneMenu id="iconSelectOneMenu"
value="#{iconController.availableIconStrings}" var="ic">
<f:selectItem itemLabel="Choose icon"
noSelectionOption="true" />
<f:selectItems
value="#{categoryController.availableIconStrings}"
var="_icon" itemValue="#{_icon}"
itemLabel="#{_icon}" />
<p:column>
<p:button id="iconButton" icon="#{ic}" />
</p:column>
<p:column>
<h:outputText value="#{ic}" />
</p:column>
</p:selectOneMenu>
Now, You are facing a bug because you are using a List<String> as explained on this SO question:
So, if the item value is an instance of String, custom content via p:column is totally ignored.
You can find a workaround in the same post: https://stackoverflow.com/a/32740430/2118909
Use inputGroup
<div class="ui-inputgroup">
<div class="ui-inputgroup-addon"><i class="pi pi-user"></i></div>
<p:inputText placeholder="Username"/>
</div>
https://www.primefaces.org/showcase/ui/input/inputGroup.xhtml
See https://www.primefaces.org/showcase/ui/input/oneMenu.xhtml for an example:
<p:outputLabel value="Icons" />
<h:panelGroup styleClass="ui-inputgroup">
<h:panelGroup id="icon" styleClass="ui-inputgroup-addon">
<i class="pi pi-#{selectOneMenuView.icon}"/>
</h:panelGroup>
<p:selectOneMenu value="#{selectOneMenuView.icon}" var="item">
<f:selectItems value="#{['flag','wallet','map','link']}" var="item" itemLabel="#{item}"
itemValue="#{item}" />
<p:column><i class="pi pi-#{item}" /> #{item} </p:column>
<p:ajax update="#parent:#parent:icon" />
</p:selectOneMenu>
</h:panelGroup>
It is a workaround, yes, but it's the best option currently.
See also:
https://github.com/primefaces/primefaces/issues/6140
I have a datatable on a page with columns Unit/Set, Vehicle, Next Maintenance, Day 1,...,Day 7. I have two radio buttons also to change the sorting of the data, when I change to the other radio button which sorts by Date instead of Unit/Set the columns should change to Date, A Exams, B Exams, C Exams,...
I assume I need to create two datatables and then use the rendered attribute to decide which table is shown depending on which sort is selected.
<p:dataTable id="dataTableEnquiryNextDue" styleClass="editable-datatable"
rows="20"
scrollable="true"
frozenColumns="2"
rendered=>
<p:column headerText="Unit/Set" />
<p:column headerText="Vehicle" />
<p:column headerText="Next Maintenance" />
<p:column headerText="Day 1" />
<p:column headerText="Day 2" />
<p:column headerText="Day 3" />
<p:column headerText="Day 4" />
<p:column headerText="Day 5" />
<p:column headerText="Day 6" />
<p:column headerText="Day 7" />|
</p:dataTable>
This is my code for the datatable, except I have left the rendered blank at the minute, I believe I'll have to make some kind of bean, I think it will get the value of the radio buttons then I will have something like
rendered="#{Bean.searchSort == Unit}
or
rendered="#{Bean.searchSort == Date}
I have created a bean with the following code
#ManagedBean
#ViewScoped
public class DepotWorkloadBean implements Serializable {
public enum Sort {
UNIT, DATE
}
private Sort sortMode = Sort.UNIT;
public Sort getSortMode() {
return sortMode;
}
public void enterUnitSort() {
sortMode = Sort.UNIT;
}
public void enterDateSort() {
sortMode = Sort.DATE;
}
}
And in my table added the line
rendered="#{depotWorkloadBean.sortMode == 'UNIT'}"
I have also created my other table the same way but with
rendered="#{depotWorkloadBean.sortMode == 'DATE'}"
and different columns.
For my radio buttons I have written
<p:radioButton id="UnitSetNumber" for="customRadio3" itemIndex="0"
onchange="#{depotWorkloadBean.enterUnitSort}" update="dataTableDaySortUnit dataTableDaySortDate"/>
<p:radioButton id="DateDue" for="customRadio3" itemIndex="1"
onchange="#{depotWorkloadBean.enterDateSort}" update="dataTableDaySortUnit dataTableDaySortDate"/>
At the moment I am getting an error saying
The class 'DepotWorkloadBean' does not have the property 'enterUnitSort'.
This is quite confusing as it clearly does and as far as I can tell I have spelt everything correctly. I'm still not sure if my approach is actually correct though, so again any advice will be appreciated.
Here is my selectOneRadio
<p:selectOneRadio id="customRadio3" layout="custom">
<f:selectItem itemLabel="UnitSetNumber" itemValue="1" binding="{depotWorkloadBean.enterUnitSort}"
update=":mainForm"/>
<!-- <f:ajax listener="#{depotWorkloadBean.enterUnitSort}" render="#all"/> -->
<f:selectItem itemLabel="DateDue" itemValue="2" binding="{depotWorkloadBean.enterDateSort}"
update=":mainForm"/>
<!-- <f:ajax listener="#{depotWorkloadBean.enterDateSort}" render="#all"/> -->
<f:selectItem itemLabel="DueInValue" itemValue="3" />
</p:selectOneRadio>
EDIT: Here is my updated selectOneRadio
<p:selectOneRadio id="customRadio3" layout="custom"
value="#{depotWorkloadBean.sortMode}"
update=":mainForm">
<f:selectItem itemLabel="UNIT.name" itemValue="UNIT" value="#{depotWorkloadBean.sortMode}"
var="UNIT"/>
<!-- <f:ajax listener="#{depotWorkloadBean.enterUnitSort}" render="#all"/> -->
<f:selectItem itemLabel="DATE.name" itemValue="DATE" value="#{depotWorkloadBean.sortMode}"
var="DATE"/>
<!-- <f:ajax listener="#{depotWorkloadBean.enterDateSort}" render="#all"/> -->
<f:selectItem itemLabel="DueInValue" itemValue="3" />
</p:selectOneRadio>
And here is my updated bean
#ManagedBean
#ViewScoped
public class DepotWorkloadBean implements Serializable {
public enum Sort {
UNIT, DATE
}
private Sort sortMode = Sort.UNIT;
public Sort getSortMode() {
return sortMode;
}
public Sort[] getSortValues() {
return Sort.values();
}
public void setSortMode(Sort sortMode) {
this.sortMode = sortMode;
}
}
EDIT: After a bit of thinking I have taken a new approach, so now my radio button group is like so:
<!-- <f:facet name="actions"> -->
<p:selectOneRadio id="customRadio3" layout="custom"
partialSubmit="true"
value="#{depotWorkloadBean.selectSort}">
<p:ajax update="mainForm" listener="#{depotWorkloadBean.updateSortMode}"/>
<f:selectItem itemLabel="UnitSet" itemValue="UnitSet"/>
<f:selectItem itemLabel="DateDue" itemValue="DateDue"/>
<f:selectItem itemLabel="DueInValue" itemValue="DueInValue"/>
</p:selectOneRadio>
<!-- </f:facet> -->
I have commented out the facet tag as it causes the error
"javax.servlet.ServletException" and I have no idea why.
My tables are as they were before except the rendered line is now
rendered="#{depotWorkloadBean.sortMode == 'UnitSet'}">
and similar for 'DateDue'. And my bean is as follows:
#ManagedBean
#ViewScoped
public class DepotWorkloadBean implements Serializable {
private static final Log log = LogFactory.getLog(DepotWorkloadBean.class);
/*public enum Sort {
UNIT, DATE
}
private Sort sortMode = Sort.UNIT;*/
private String sortMode = "UnitSet";
private String selectSort = "UnitSet";
public void updateSortMode () {
log.info("In updateSortMode " + " State [" + selectSort + "]");
sortMode = selectSort;
}
public String getSortMode() {
return sortMode;
}
public void setSortMode(String sortMode) {
this.sortMode = sortMode;
}
public String getSelectSort() {
return selectSort;
}
public void setSelectSort(String selectSort) {
log.info("Setting selectSort to [" + selectSort + "]");
this.selectSort = selectSort;
sortMode = selectSort;
}
I have only just found out about the log and it seems very useful. When my page builds and I click between the radio buttons my log records 'In updateSortMode State []' "Setting selectSort to State []" so there is clearly something going wrong in the method. The other thing I should mention is my radio buttons are actually displayed further down in the same panelGrid, like so..
<p:row>
<p:column>
<p:radioButton id="UnitSetNumber" for="customRadio3" itemIndex="0"/>
</p:column>
<p:column>
<h:outputLabel for="UnitSetNumber" value="Unit/set number" />
</p:column>
</p:row>
<p:row>
<p:column>
<p:radioButton id="DateDue" for="customRadio3" itemIndex="1"/>
</p:column>
<p:column>
<h:outputLabel for="DateDue" value="Date due" />
</p:column>
</p:row>
<p:row>
<p:column>
<p:radioButton id="DueInValue" for="customRadio3" itemIndex="2" />
</p:column>
<p:column>
<h:outputLabel for="DueInValue" value="Due in value" />
</p:column>
</p:row>
Not sure if that would affect the ajax listener?
Thanks
You don't need an onchange listener, the update= attribute will do the job.
Use a <p:selectOneRadio> with a nested <f:selectitems> that will set the sortMode value of your bean (you might need a converter). Then ensure the parent component of both tables is updated upon selection. This will re-evaluate the rendered= attributes of your tables with the newly set sortMode valule.
Example:
The view:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>TEST</title>
</h:head>
<h:body>
<h:form>
<p:selectOneRadio id="radiogroup"
value="#{testController.selectedValue}">
<f:ajax render=":content"/>
<f:selectItems value="#{testController.valuesTypes}"
var="val"
itemLabel="#{val.name()}"
itemValue="#{val}"/>
</p:selectOneRadio>
</h:form>
<h:form id="content">
<p:outputPanel rendered="#{testController.selectedValue eq 'VALUEA'}">
Value A panel
</p:outputPanel>
<p:outputPanel rendered="#{testController.selectedValue eq 'VALUEB'}">
Value B panel
</p:outputPanel>
<p:outputPanel rendered="#{testController.selectedValue eq 'VALUEC'}">
Value C panel
</p:outputPanel>
</h:form>
</h:body>
</html>
And the bean:
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class TestController {
public enum ValueTypes {
VALUEA,
VALUEB,
VALUEC
}
private ValueTypes selectedValue;
public ValueTypes getSelectedValue() {
return selectedValue;
}
public void setSelectedValue(ValueTypes selectedValue) {
this.selectedValue = selectedValue;
}
#PostConstruct
public void init() {
selectedValue = ValueTypes.VALUEA;
}
public ValueTypes[] getValuesTypes() {
return ValueTypes.values();
}
}
With primefaces I made a multicheckbox with several divisions to choose. After clicking the submit Button the chosen divisions should be listed in a datatable with the associated items in a subtable. There could be 0 - n items which should be shown in the subtable.
division1 -> item1, item2
division2 -> item3, item4, item5
The first impression of the webpage looks fine. When I only choose one division and press submit the fitting items will be shown. But when I want to display other items they get overwritten. e.g. when I choose division2 it will display the items item1, item2 and item 5.
How can I make it so that the items will be loaded correctly every time?
I also changed the subtable to a nested datatable, but the behaviour was the same.
I've primefaces version 4.0
Below is my code:
division_list.xhtml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Gruppenverwaltung</title>
</h:head>
<h:body>
<f:view>
<h:form id="myForm">
<h2>
<h:outputText value="Division List" />
</h2>
<h:outputText value="Grid: " />
<p:selectOneRadio id="grid" value="#{divisionController.selectedDivisions}" layout="grid" columns="3"
converter="DivisionConverter">
<f:selectItems value="#{divisionController.divisions}" />
</p:selectOneRadio>
<p:commandButton value="Submit" update=":myForm" />
<p:dataTable id="dtDivisions" value="#{divisionController.selectedDivisions}" var="division">
<p:subTable id="stItems" var="item" value="#{division.items}">><f:facet name="header">
<h:outputText value="#{division.name}" />
</f:facet>
<p:column>
<h:inputText value="#{item.name}" />
</p:column>
<p:column>
<p:commandButton icon="ui-icon-disk" action="#{divisionController.doUpdateItem(item)}" />
<p:commandButton icon="ui-icon-trash" oncomplete="confirm.show()">
<f:setPropertyActionListener target="#{divisionController.selectedItem}" value="#{item}" />
</p:commandButton>
</p:column>
</p:subTable>
</p:dataTable>
</h:form>
<p:confirmDialog message="Gewählter Eintrag löschen?" widgetVar="confirm"> --><h:form
id="formDialog">
<p:commandButton value="Yes" action="#{divisionController.doDeleteItem}"
styleClass="ui-confirmdialog-yes" icon="ui-icon-check" oncomplete="confirmation.hide()" />
<p:commandButton value="No" type="button" onclick="confirm.hide()" styleClass="ui-confirmdialog-no"
icon="ui-icon-close" />
</h:form>
</p:confirmDialog>
</f:view>
</h:body>
</html>
DivisonController.java:
...
#ManagedBean
#ViewScoped
public class DivisionController implements Serializable {
...
private List<DivisionDto> divisions;
private List<DivisionDto> selectedDivisions;
...
#PostConstruct
public void init() throws MappingTOException {
....
if (divisions == null) {
divisions = club.getDivisions();
}
}
...
DivisionDto.java
...
public class DivisionDto {
....
private List<ItemDto> items;
private String name;
...
ItemDto.java
...
public class ItemDto {
...
private DivisionDto division;
private String name;
...
DivisionConverter.java
#FacesConverter(value = "DivisionConverter")
public class DivisionConverter implements Converter {
private static Map<String, DivisionDto> divisionCache = new HashMap<String, DivisionDto>();
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
DivisionDto val = divisionCache.get(value);
if (val == null) {
val = new DivisionDto();
val.setName(value);
}
return val;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value instanceof DivisionDto) {
DivisionDto division = (DivisionDto) value;
divisionCache.put(division.getName(), division);
return division.getName();
} else {
return "";
}
}
}
I would be really grateful for any help.
I solved the issue wie a datatable in a datatable and put a filter on the first datatable. Now it works as expected.
I have a JSF 2 form like this:
<h:form>
<h:panelGrid columns="2">
<a4j:repeat value="#{dialog.departments}" var="depart">
<h:inputText value="#{depart.name}"/>
<h:selectOneRadio value="#{depart.hasSubdepartment}">
<f:ajax render="#form" execute="#form" immediate="true"/>
<f:selectItem itemValue="#{true}"/>
<f:selectItem itemValue="#{false}"/>
</h:selectOneRadio>
<a4j:repeat value="#{depart.subdepartments}" var="sub" rendered="#{depart.hasSubdepartment}">
<h:inputText value="#{sub.name}"/>
<h:outputText value=" " />
</a4j:repeat>
</a4j:repeat>
</h:panelGrid>
</h:form>
I have simply the form. As you could see, this form displays data structure of departments like a tree.
What I want to implements is that if user switch the radio button to true, the sub-departments will be displayed, if switch to false, the sub-departments will be hidden.
The problem is that:
If the execute value of the f:ajax tag is set to #form, the validation of the backing beans such as #NotNull and #Size will be called. But we don't want to call the validation now since we do not want to save the data now.
If the execute value of the f:ajax tag is set to #this, it seems that the after the ajax request, the value of the radio reverts. For example, if the radio value is false, and we click true, then after the ajax request, the value go back to false, and the sub-department part is not rendered. This will not happen if execute is set to #form.
Thanks very much if you have any idea or hint.
I don't have a Richfaces integrated testing environment, however I've achieved what you want in plain JSF (that's why it could be an ajax4jsf specific issue). Here you have a test case which works and follows SSCCE standards. Tested with Mojarra 2.1.26 & Tomcat 6:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
<h:form>
<h:panelGrid columns="2">
<ui:repeat value="#{dialog.departments}" var="depart">
<h:inputText value="#{depart.name}" />
<h:selectOneRadio value="#{depart.hasSubdepartments}">
<f:ajax render="#form" immediate="true" />
<f:selectItem itemValue="#{true}" />
<f:selectItem itemValue="#{false}" />
</h:selectOneRadio>
<h:panelGroup id="subdepartmentPanel"
rendered="#{depart.hasSubdepartments}">
<ui:repeat value="#{depart.subdepartments}" var="sub">
<h:inputText value="#{sub.name}" />
</ui:repeat>
</h:panelGroup>
</ui:repeat>
</h:panelGrid>
</h:form>
</h:body>
</html>
#ManagedBean
#ViewScoped
public class Dialog {
public class Department {
private String name;
private List<Department> subdepartments = new ArrayList<Dialog.Department>();
private boolean hasSubdepartments;
public Department(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Department> getSubdepartments() {
return subdepartments;
}
public boolean isHasSubdepartments() {
return hasSubdepartments;
}
public void setHasSubdepartments(boolean hasSubdepartments) {
this.hasSubdepartments = hasSubdepartments;
}
public void setName(String name) {
this.name = name;
}
public void setSubdepartments(List<Department> subdepartments) {
this.subdepartments = subdepartments;
}
}
private List<Department> departments = new ArrayList<Dialog.Department>();
public Dialog() {
// Create departments and subdepartments
departments.add(new Department("First Department"));
Department d = new Department("Second department");
d.getSubdepartments().add(new Department("Subdepartment"));
departments.add(d);
}
public List<Department> getDepartments() {
return departments;
}
}