This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 7 years ago.
I have a jsf form in my application which should display several input fields for creating / editing employees. There exists several departments which I want to display with a <h:selectOneMenu>. My other components are basically primefaces components.
If I select an existing employee from my datatable, the department is set correctly (in frontend and bean). I checked the converter and it's getAsString() method in debugging mode. Both seem to work fine.
But when I refresh the page with [F5] it changes the value in the <h:selectOneMenu> back to it's previous one but the bean's value is still fine. It seems that the binding between my session bean and the jsf component isn't working properly.
In addition, there's another problem when I want to save any employee. The validation shows me that the selectOneMenu value is invalid. This error occurs after the getAsObject() method successfully returns my department pojo. I didn't define any validators on this specific component but I use several input components who must not be empty. This error might occur because there's a problem with setting the value as I stated above.
DepartmentConverter.java
#ManagedBean(name="departmentConverter")
public class DepartmentConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
DepartmentDAOImpl deptUtils = new DepartmentDAOImpl();
try {
int code = Integer.parseInt(value);
return deptUtils.getDepartmentById(code);
} catch (NumberFormatException nfe) {
System.out.println("Couldn't transform department code from string to int");
nfe.printStackTrace();
}
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return ((Department) value).getCode() + "";
}
}
SampleJSFBean.java
#ManagedBean(name = "sampleBean")
#SessionScoped
public class SampleJSFBean {
private Task employee;
private List<Task> employees;
private List<Department> departments;
private Department department;
public String showEditEmployeePanel() {
// shows panel
}
public String updateEmployee() {
// saves employee
}
// getter and setter
}
registration.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition 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" template="/templates/BasicTemplate.xhtml">
<ui:define name="content">
<h:form id="formResult">
<p:panel>
<p:dataTable id="employee" var="task" value="#{sampleBean.employees}">
<p:column headerText="Code">
<h:outputText value="#{task.employee.code}" />
</p:column>
<p:column headerText="Name">
<h:outputText value="#{task.employee.lastname}" />
</p:column>
<p:column headerText="Department">
<h:outputText value="#{task.employee.department.name}" />
</p:column>
<p:column headerText="edit">
<p:commandButton id="btnMut" icon="ui-icon-pencil" title="edit employee" disabled="#{task.jobActive == true}" action="#{sampleBean.showEditEmployeePanel}"
update=":formEmployee" resetValues="true">
<f:setPropertyActionListener value="#{task}" target="#{sampleBean.task}" />
</p:commandButton>
</p:column>
</p:dataTable>
</p:panel>
</h:form>
<h:form id="formEmployee">
<p:growl autoUpdate="false" />
<p:panel id="panelEmployee">
<h:outputText value="Lastname" styleClass="labelForm" />
<p:inputText id="inputLastname" value="#{sampleBean.task.employee.lastname}" required="true" requiredMessage="Please enter lastname." />
<br />
<h:outputText value="Department" styleClass="labelForm" />
<h:selectOneMenu value="#{sampleBean.department}" converter="#{departmentConverter}">
<f:selectItems value="#{sampleBean.departments}" var="dept" itemLabel="#{dept.code} - #{dept.name}" />
</h:selectOneMenu>
<br />
<p:commandButton value="save" action="#{sampleBean.updateEmployee}" icon="ui-icon-disk" update=":formResult :formEmployee" />
</p:panel>
</h:form>
</ui:define>
Have you tried with primefaces component instead <h:selectOneMenu> use <p:selectOneMenu>.
I'm not sure it helps, but I always use primeFaces's selectOneMenu and always works.
Related
I am building a simple component in JSF (Mojarra 2.1.x) where I have to access parent ui components to update them, currently I'm using binding to achieve this, but it only works as long as I don't use the component more than once on the same page.
So I need a solution that would allow me to use the component multiple times on same page.
In the following code I'm updating commandButton with binding="#{msButton}" and panel with binding="#{msPanel}":
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:component 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:c="http://java.sun.com/jsp/jstl/core"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:layout="http://sterz.stlrg.gv.at/jsf/layout"
xmlns:p="http://primefaces.org/ui">
<cc:interface>
<cc:attribute name="controller" required="true" />
<cc:attribute name="converter" required="true" />
</cc:interface>
<cc:implementation>
<p:commandButton id="msButton#{cc.attrs.controller.class.getSimpleName()}" binding="#{msButton}" value="#{msg.mehr} (#{cc.attrs.controller.itemList.size()})" type="button" />
<p:overlayPanel id="msOverlayPanel" for=":#{msButton.clientId}" hideEffect="fade" my="right top" at="right bottom">
<p:panel id="msPanel#{cc.attrs.controller.class.getSimpleName()}" binding="#{msPanel}" styleClass="ui-panel-fit">
<ui:repeat id="repeat" value="#{cc.attrs.controller.itemList}"
var="item">
<p:commandButton id="removeButton"
actionListener="#{cc.attrs.controller.removeItem(item)}"
icon="ui-icon-trash" update=":#{msPanel.clientId} :#{msButton.clientId}" ajax="true"
process="#this" disabled="#{cc.attrs.controller.itemList.size() == 1}"/>
<p:selectBooleanButton id="value1" value="#{item.exclude}"
offLabel="und" onLabel="und nicht" style="width:80px;">
<p:ajax event="change" process="#this" />
</p:selectBooleanButton>
<p:autoComplete converter="#{cc.attrs.converter}"
readonly="#{cc.attrs.readonly}" value="#{item.from}"
dropdown="true"
completeMethod="#{cc.attrs.controller.autocomplete}" var="gp"
itemLabel="#{gp.displayName}" itemValue="#{gp}">
<p:ajax event="itemSelect" process="#this" />
</p:autoComplete>
<h:outputText value=" #{msg.bis} " />
<p:autoComplete converter="#{cc.attrs.converter}"
readonly="#{cc.attrs.readonly}" value="#{item.to}" dropdown="true"
completeMethod="#{cc.attrs.controller.autocomplete}" var="gp"
itemLabel="#{gp.displayName}" itemValue="#{gp}">
<p:ajax event="itemSelect" process="#this" />
</p:autoComplete>
<br />
</ui:repeat>
<hr />
<p:commandButton id="addButton" actionListener="#{cc.attrs.controller.addItem}"
icon="ui-icon-plus" value="#{msg.zufuegen}" update="#parent :#{msButton.clientId}"
ajax="true" process="#this"/>
</p:panel>
</p:overlayPanel>
</cc:implementation>
</ui:component>
Any help is much apprecieted.
The solution is to use the faces component bean
#FacesComponent("com.xxx.MultiselectorIdComponent")
public class MultiselectorIdComponent extends UINamingContainer
{
UIComponent msPanel;
// getters/settter and other ui compunents
}
tell the component interface what faces component bean to use
<cc:interface componentType="com.xxx.MultiselectorIdComponent">
bind the JSF component to the one in the faces component bean
<p:panel binding="#{cc.msPanel}"/>
and to access the components, for example to update the component, we use the binding
<p:commandButton value="My Button" update=":#{cc.msPanel.clientId}"/>
ALSO:
A good practice is to use a parent container (like <div>) with the following ID
<div id="#{cc.clientId}">
Hope this helps,
Regards
You could target the components for update by their style class
<p:commandButton styleClass="msButton" ... />
<p:panel styleClass="msPanel" ... />
And I guess you update them from addButton, which would look like this
<p:commandButton id="addButton" update="#(.msButton, .msPanel)" ... />
It should have no problems working with many cc instances on the same page.
UPDATE
You can try with update="#composite", which should refresh the whole custom component. Or, the cumbersome update="#parent #parent:#parent:#parent:#child(1)" which should target panel and button respectively. Or update="#parent #parent:#parent:#previous", which should do the same. Take a look at chapter 4.3 in Primefaces User Guide for more examples and supported keywords.
I solve similar problem by common bean "bindingBean" stored in ViewContext. BindingBean holds all binded component in internal MAP of component records. The key of hash map is an EL expression - it is factory of the component. EL is used for components creating. Components are hold in records stored in MAP in bind bean.
Example:
<h:panel binding="#{bindBean.get('msPanelFactory.getPanel()').component}"/>
Record:
public class BindingRecord {
private Object component;
private String compExpr;
public BindingRecord(String compExpr) {
this.compExpr = compExpr;
}
public Object getComponent() {
if (component == null) {
component = getValueExprValue("#{" + compExpr + "}");
}
return component;
}
public void setComponent(Object component) {
this.component = component;
}
public Object getStoredComponent() {
return component;
}
}
Binding bean:
public class BindingBean {
private final Map<String, BindingRecord> bindingMap = new HashMap<>();
public BindingRecord get(String key) {
BindingRecord result = bindingMap.get(key);
if (result == null) {
result = new BindingRecord(key);
bindingMap.put(key, result);
}
return result;
}
}
In you case you can use:
<h:panel binding="#{bindingBean.get('panelFactory.create()').component}"/>
Inside composite component you can use trick - Pass component name by composite parameter:
<h:panel binding="#{bindingBean.get('panelFactory.create('.concate(cc.attrs.componentName).concate(')')).component}"/>
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.
Sample.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<f:event listener="#{sample.dosamplelist}" type="preRenderView" />
</h:head>
<h:body>
<h:form>
<h:panelGrid id="samplesetting" columns="6" cellpadding="5">
<f:facet name="header">Name Setting</f:facet>
<h:outputLabel for="samplename" value="Name:" />
<p:inputText value="#{sample.name}" id="samplename"
required="true" label="samplename" />
</h:panelGrid>
<p:panel id="sampleview" header="Sample List">
<p:dataTable var="spl" value="#{sample.samplelist}" rowKey="#{spl.name}"
selection="#{sample.selectedname}"
selectionMode="single">
<p:column headerText="Name">
<h:outputText value="#{spl.name}" />
</p:column>
<p:column>
<p:commandButton id="one" value="View Details" action="#{sample.setSelectedsample(spl)}" update="#form:samplesetting">
</p:commandButton>
</p:column>
</p:dataTable>
</p:panel>
</h:form>
Managed Bean
#SuppressWarnings("serial")
#ManagedBean(name = "sample")
#RequestScoped
public class Sample implements Serializable
{
private String name;
private List<Sample> samplelist;
private String selectedname;
//getters and setters
public void dosamplelist(ComponentSystemEvent event)
{
List<Sample> samplelist = new ArrayList<Sample>();
Sample configA = new Sample();
configA.setName("John");
samplelist.add(configA);
Sample configB = new Sample();
configB.setName("David");
samplelist.add(configB);
this.samplelist = samplelist;
}
public void setSelectedsample(Sample smpl)
{
this.name = smpl.name;
}
}
This is the sample of little big form, and the need is, when we select the table row from the bottom, it will be display to top input box for editing purpose.
But when I press the command button it do not work. why? and what is the reason please?
Possible Problem
One obvious problem is that at the class level, you've defined:
private List<Sample> samplelist;
Then you go ahead and hide the variable in doSampleList with
List<Sample> samplelist = new ArrayList<Sample>();
Combined with the fact that you have your bean marked as #RequestScoped, it will guarantee that the content of the samplelist will not be consistent during the JSF request processing.
To Solve:
Mark your bean as #ViewScoped instead and resolve the variable hiding problem as you see fit.
Further reading:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
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;
}
}
I have got some problems with my JSF page, and (probably) with backing bean. I have got own template and I fill the content area with some pages. I have got search page with commandbutton and I would like to get data from database (JPA) and than fill the datatable.
Look at my searchpeople.xhtml:
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<ui:define name="content">
<h:form id="sampleform">
<p:accordionPanel activeIndex="-1" id="accordingpanle">
<p:tab title="User options" >
<p:growl id="growl" showDetail="true" showSummary="true"/>
<p:commandButton id="searchbutton" action="#{mb_person.search}" value="Szukaj" update="personsearchresulttable" />
</p:tab>
</p:accordionPanel>
<p:dataTable id="personsearchresulttable" var="person" value="#{mb_person.people}" widgetVar="personTable" style="margin-top: 10px" >
<p:column headerText="Id" style="width:10%">
<h:outputText value="#{person.id}" />
</p:column>
<p:column headerText="Name" style="width:20%">
<h:outputText value="#{person.name}" />
</p:column>
<p:column headerText="Surname" style="width:20%">
<h:outputText value="#{person.surname}" />
</p:column>
<p:column headerText="Company">
<h:outputText value="#{person.companyName}" />
</p:column>
<p:column style="width:4%" headerText="Open">
<h:link outcome="persondetails" value="Open">
<!--<f:param name="personid" value="#{person.id}"/>-->
<f:param name="personid" value="10076"/>
</h:link>
</p:column>
</p:dataTable>
</h:form>
</ui:define>
</ui:composition>
And my backingbean with EJB injection.
#ManagedBean(name="mb_person")
public class MB_Person implements Serializable{
#EJB
private PersonFacade personFacade;
private List<PersonAndCompany> people = new ArrayList<PersonAndCompany>();
public MB_Person() {
}
public List<PersonAndCompany> getPeople() {
return people;
}
public void setPeople(List<PersonAndCompany> people) {
this.people = people;
}
public void search() {
int[] range = {0,5};
setPeople(personFacade.findPersonWithMoreThanXProjects(20));
setPeople(personFacade.findPersonAndCompanyName(range));
for(PersonAndCompany p:people){
System.out.println(p.getName());
}
}
public String goToPersonDatailPage(int id){
return "persondetails.jsf?personid="+id;
}
}
I tried small test and printout all data in method search and I received good results.
Someone can help me how to update dataTable using ajax? In this form I have got an exception
Cannot find component with identifier "personsearchresulttable" referenced from "sampleform:accordingpanle:searchbutton".
Relative client IDs are searched relative to parent NamingContainer component. The <p:accordionPanel> is by itself a NamingContainer. So the relative client ID personsearchresulttable would be searched inside the context of the <p:accordionPanel>. However, it's actually outside the panel, inside the <h:form>.
You need to change the relative client ID to be an absolute client ID.
update=":sampleform:personsearchresulttable"
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"