I was having some problem with password validation, which #BalusC help me out, here.
But after I insert the validation code in my form, when I call the controller method, nothing happens.
Here goes my JSF page:
Register.xhtml
<!DOCTYPE html>
<html lang="pt-br"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<h:head>
<title>TITLE</title>
</h:head>
<h:body>
<h:form id="form">
<h:panelGrid columns="3" >
<h:outputLabel for="name" value="Nome:" />
<h:inputText id="name" value="#{register.person.name}" >
<f:ajax event="blur" listener="#{register.validateName}" render="m_name" />
</h:inputText>
<rich:message id="m_name" for="name" ajaxRendered="false"/>
// some fields ..
<h:outputLabel for="password" value="Password" />
<h:inputSecret id="password" value="#{register.user.password}">
<f:validator validatorId="confirmPasswordValidator" />
<f:attribute name="confirm" value="#{confirmPassword.submittedValue}" />
<f:ajax event="blur" execute="password confirm" render="m_password" />
</h:inputSecret>
<rich:message id="m_password" for="password" />
<h:outputLabel for="confirm" value="Senha (novamente):" />
<h:inputSecret id="confirm" binding="#{confirmPassword}" >
<f:ajax event="blur" execute="password confirm" render="m_password m_confirm" />
</h:inputSecret>
<rich:message id="m_confirm" for="confirm" />
<h:commandButton value="Register" action="#{register.registerPerson}" >
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:outputText value="#{register.recordStatus}" id="out" />
<a4j:status>
<f:facet name="start">
<h:graphicImage name="loader.gif" library="image"/>
</f:facet>
</a4j:status>
</h:panelGrid>
</h:form>
</h:body>
</html>
So when I fill the form and try to register, nothing happens, not even any exception it's lauched.
The passwod validator (thanks BalusC mate):
#FacesValidator("confirmPasswordValidator")
public class ConfirmPasswordValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
String password = (String) value;
String confirm = (String) component.getAttributes().get("confirm");
if (password == null || confirm == null) {
return; // Just ignore and let required="true" do its job.
}
if (!password.equals(confirm)) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "password not equal"));
}else{
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_INFO, null, "ok"));
}
}
}
I think this problem is very weird, I really don't know what's happening here.
Thanks guys.
You threw a ValidatorException on a succesful match.
if (!password.equals(confirm)) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "password not equal"));
} else {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_INFO, null, "ok"));
}
This causes JSF to block the form submit. The severity doesn't matter. A validator exception is a validator exception. It indicates a vaildation failure.
Rather use FacesContext#addMessage() instead.
if (!password.equals(confirm)) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "password not equal"));
} else {
context.addMessage(component.getClientId(), new FacesMessage(FacesMessage.SEVERITY_INFO, null, "ok"));
}
Related
I'm trying to load some data after a user logs in to my app. I need the username to load data specific to the user. The problem I'm having is that I have a SessionScoped backing bean that contains the code to log the user in, and then I have a ViewScoped page specific backing bean (which injects the SessionScoped bean) which is to load the data for the page.
Currently this is the code that I have and I get a null pointer when loading the data because the username doesn't exist when the loadData() method is called.
I'm having a hard time coming up with a solution to this problem as I'd like to NOT have to put the login dialog on every page and keep it in the template.xhtml file if possible.
template.xhtml
...
<!-- Login Dialog -->
<p:dialog id="loginDialog" header="Login" widgetVar="loginWidget" modal="true" visible="#{!accessBacking.hasAccess}" closable="false">
<h:form id="loginForm">
<p:messages id="loginFormMessages" severity="error" autoUpdate="true" showDetail="true" />
<h:panelGrid columns="2" cellspacing="10" width="300">
<p:outputLabel for="username" value="Username" />
<p:inputText id="username" value="#{accessBacking.username}" required="true" requiredMessage="Username is Required" />
<p:outputLabel for="password" value="Password" />
<p:password id="password" value="#{accessBacking.password}" required="true" requiredMessage="Password is Required" />
<h:panelGroup></h:panelGroup>
<h:panelGroup>
<p:commandButton value="Login" styleClass="ui-priority-primary" actionListener="#{accessBacking.checkViewAccess}" oncomplete="handleAuthenticationRequest(xhr, status, args)" update="loginFormMessages" />
</h:panelGroup>
</h:panelGrid>
</h:form>
</p:dialog>
...
userGroups.xhtml
<?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">
<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:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:body>
<f:metadata>
<f:event type="preRenderView" listener="#{userGroupBacking.setCurrentMenu}" />
</f:metadata>
<ui:composition template="/templates/template.xhtml">
<p:dataTable var="user" value="#{userGroupBacking.users}" editable="true" id="userTable">
...
AccessBacking.java
#ManagedBean(name="accessBacking")
#SessionScoped
public class AccessBacking {
private String username;
private String password;
public boolean checkViewAccess() {
Access access = new Access();
if(access.authenticate(username, password)) {
// user is logged in
}
}
}
UserGroupBacking
#ManagedBean(name="userGroupBacking")
#ViewScoped
public class UserGroupBacking {
#ManagedProperty(value="#{accessBacking}")
private AccessBacking accessBacking;
public void setAccessBacking(AccessBacking accessBacking) {
this.accessBacking = accessBacking;
}
#PostConstruct
public void init() {
loadData();
}
/**
* Loads the data for the page
*/
public void loadData() {
Dao dao = new Dao(ds);
users = dao.findAllUsers(accessBacking.getUsername(), accessBacking.getRoles()); // NULL POINTER BECAUSE ACCESSBACKING.GETUSERNAME() IS NULL SINCE THE USER HASN'T LOGGED IN YET.
}
}
I've figured out a good solution by using ui:param. Basically I set a ui:param with my backing bean value in my page specific xhtml and then reference that ui:param in my template.
Updated code from question with new solution:
template.xhtml
...
<!-- NOTE the 'myBacking' instead of the 'userGroupBacking' -->
<!-- Login Dialog -->
<p:dialog id="loginDialog" header="Login" widgetVar="loginWidget" modal="true" visible="#{!myBacking.hasAccess}" closable="false">
<h:form id="loginForm">
<p:messages id="loginFormMessages" severity="error" autoUpdate="true" showDetail="true" />
<h:panelGrid columns="2" cellspacing="10" width="300">
<p:outputLabel for="username" value="Username" />
<p:inputText id="username" value="#{accessBacking.username}" required="true" requiredMessage="Username is Required" />
<p:outputLabel for="password" value="Password" />
<p:password id="password" value="#{accessBacking.password}" required="true" requiredMessage="Password is Required" />
<h:panelGroup></h:panelGroup>
<h:panelGroup>
<p:commandButton value="Login" styleClass="ui-priority-primary" actionListener="#{myBacking.checkViewAccess}" oncomplete="handleAuthenticationRequest(xhr, status, args)" update="loginFormMessages" />
</h:panelGroup>
</h:panelGrid>
</h:form>
</p:dialog>
...
userGroups.xhtml
<?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">
<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:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:body>
<f:metadata>
<f:event type="preRenderView" listener="#{userGroupBacking.setCurrentMenu}" />
</f:metadata>
<!-- THIS IS PART OF THE SOLUTION -->
<ui:param name="myBacking" value="#{userGroupBacking}" />
<ui:composition template="/templates/template.xhtml">
<p:dataTable var="user" value="#{userGroupBacking.users}" editable="true" id="userTable">
...
AccessBacking.java
#ManagedBean(name="accessBacking")
#SessionScoped
public class AccessBacking {
private String username;
private String password;
public boolean checkViewAccess() {
Access access = new Access();
if(access.authenticate(username, password)) {
// user is logged in
}
}
}
UserGroupBacking
#ManagedBean(name="userGroupBacking")
#ViewScoped
public class UserGroupBacking {
#ManagedProperty(value="#{accessBacking}")
private AccessBacking accessBacking;
public void setAccessBacking(AccessBacking accessBacking) {
this.accessBacking = accessBacking;
}
#PostConstruct
public void init() {
loadData();
}
// CHECKS AGAINST ACCESSBACKING
public boolean isHasAccess() {
return accessBacking.isHasAccess();
}
// CHECKS AGAINST ACCESSBACKING
public boolean checkViewAccess() {
return accessBacking.checkViewAccess();
}
/**
* Loads the data for the page
*/
public void loadData() {
Dao dao = new Dao(ds);
users = dao.findAllUsers(accessBacking.getUsername(), accessBacking.getRoles());
}
}
I'm having problems with relatively simple JSF2 site with Primefaces. I'm using Primefaces 3.5 and WebSphere Application Server v7.0
I have a page with a p:datatable which displays documents. I would like to be able to add, edit and delete said documents with a confirm/input -dialog. But when I click the Add document -button, input the name for the document and click Save, only an empty row apperas to the table. When I click the edit button and give it a proper name it is saved accordingly. But if I try to edit another row, the dialog displays the last document's name I edited.
There might be something wrong with the references, but I can't wrap my head around it. I have tried to research the subject but whit no avail. When a new document is added(or edited) the setter is called twice so I wonder if it has anything to do with this http://code.google.com/p/primefaces/issues/detail?id=4681
Here's the code-files:
test.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.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>test</title>
<meta http-equiv="Content-Type"
content="application/xhtml+xml; charset=UTF-8" />
</h:head>
<h:body>
<h:form>
<p:dataTable var="document" value="#{testMB.list}" id="documentTable"
paginator="true" rows="15" paginatorPosition="bottom"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}"
emptyMessage="No documents">
<f:facet name="header">
List of documents
</f:facet>
<p:column headerText="Document">
<h:outputText value="#{document.name}" />
</p:column>
<p:column width="70">
<p:commandButton icon="ui-icon-trash"
oncomplete="deleteDocumentDlg.show()"
style="float:right;width:32px;height:32px;top-margin:0px;bottom-margin:0px;top-padding:0px;bottom-padding:0px;">
<f:setPropertyActionListener value="#{document}"
target="#{testMB.document}" />
</p:commandButton>
<p:commandButton icon="ui-icon-pencil"
oncomplete="editDocumentDlg.show()"
style="float:right;width:32px;height:32px;top-margin:0px;bottom-margin:0px;top-padding:0px;bottom-padding:0px;"
action="#{testMB.saveChangesToDocument}">
<f:setPropertyActionListener value="#{document}"
target="#{testMB.document}" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:commandButton value="New document"
oncomplete="newDocumentDlg.show()" style="float:right" />
<!-- Add new document -dialog -->
<p:dialog widgetVar="newDocumentDlg" id="newDocumentDialog"
header="Add new document" message="Add new document"
hideEffect="fade" showEffect="fade" resizable="true" closable="true"
lazy="true" width="600">
<h:panelGrid columns="3">
<h:outputText value="Name" />
<p:spacer width="10" height="10" />
<p:inputText value="#{testMB.document.name}" width="35"
maxlength="128" />
</h:panelGrid>
<br />
<h:panelGroup layout="block" style="text-align: right">
<p:commandButton value="Save" action="#{testMB.addDocument}"
oncomplete="newDocumentDlg.hide();" update="documentTable">
</p:commandButton>
<p:commandButton value="Cancel" oncomplete="newDocumentDlg.hide();"
action="#{testMB.cancelAction}" />
</h:panelGroup>
</p:dialog>
<!-- Delete document -dialog -->
<p:dialog widgetVar="deleteDocumentDlg" id="deleteDocumentDialog"
header="Delete document" message="Delete document" hideEffect="fade"
showEffect="fade" resizable="false" closable="true" lazy="true">
<h:outputText value="Delete document?" />
<h:panelGroup layout="block" style="text-align: right">
<p:commandButton value="Delete" action="#{testMB.deleteDocument}"
oncomplete="deleteDocumentDlg.hide();" update="documentTable">
</p:commandButton>
<p:commandButton value="Cancel"
oncomplete="deleteDocumentDlg.hide();"
action="#{testMB.cancelAction}" />
</h:panelGroup>
</p:dialog>
<p:dialog widgetVar="editDocumentDlg" id="editDocumentDialog"
header="Edit document" message="Edit document" hideEffect="fade"
showEffect="fade" resizable="true" closable="true" lazy="true"
width="600">
<h:panelGrid columns="3">
<h:outputText value="Name" />
<p:spacer width="10" height="10" />
<p:inputText value="#{testMB.document.name}" width="35"
maxlength="128" />
</h:panelGrid>
<br />
<h:panelGroup layout="block" style="text-align: right">
<p:commandButton value="Save" action="#{testMB.saveChanges}"
oncomplete="editDocumentDlg.hide();" update="documentTable">
</p:commandButton>
<p:commandButton value="Cancel" oncomplete="editDocumentDlg.hide();"
action="#{testMB.cancelAction}" />
</h:panelGroup>
</p:dialog>
</h:form>
</h:body>
</html>
testMB.java
import Document
#ManagedBean
#ViewScoped
public class testMB implements Serializable {
private Document document;
ArrayList<Document> list;
#PostConstruct
public void alusta() {
System.err.println("POSTCONSTRUCT");
document = new Document();
list = new ArrayList();
}
public String addDocument() {
System.err.println("Adding new document: " + document.getName());
list.add(document);
document = new Document();
return null;
}
public String deleteDocument() {
System.err.println("Deleting document: " + document.getName());
list.remove(document);
document = new Document();
return null;
}
public String saveChanges() {
System.err.println("Saving changes to document: " + document.getName());
list.get(list.indexOf(document)).setName(document.getName());
document = new Document();
return null;
}
public String cancelAction() {
document = new Document();
return null;
}
public void setDocument(Document document) {
System.err.println("Document set to: " + document.getName());
this.document = document;
}
public Document getDocument() {
return document;
}
public void setList(ArrayList<Document> list) {
this.list = list;
}
public ArrayList<Document> getList() {
return list;
}
}
Document.java
public class Document {
private String name;
public Document() {
System.out.println("Document's constructor");
name = null;
}
public Document(Document src) {
System.out.println("Document's copy constructor");
this.name = src.name;
}
public void setName(String name) {
System.err.println("Name set to " + name);
this.name = name;
}
public String getName() {
return name;
}
}
I'd be grateful for your feedback.
Your code has some problems . But the problem I can see is here
<!-- Add new document -dialog -->
<p:dialog widgetVar="newDocumentDlg" id="newDocumentDialog"
header="Add new document" message="Add new document"
hideEffect="fade" showEffect="fade" resizable="true" closable="true"
lazy="true" width="600">
<h:panelGrid columns="3">
<h:outputText value="Name" />
<p:spacer width="10" height="10" />
<p:inputText value="#{testMB.document.name}" width="35"
maxlength="128" />
</h:panelGrid>
You cannot set input text to current document name.
Instead use another variable to hold value for new document name like
private String newName;
public String getNewName() {
return newName;
}
public void setNewName(String newName) {
this.newName = newName;
}
Then change your jspx
<h:panelGrid columns="3">
<h:outputText value="Name" />
<p:spacer width="10" height="10" />
<p:inputText value="#{testMB.newName}" width="35"
maxlength="128" />
</h:panelGrid>
then your addDocument() becomes
document.setName(newName);
documentList.add(document);
document = new Document();
I hope that helps.
I want to update a selectOneMenu in form1 after submitting the commandbutton in form2. It is now only visible after a refresh of the page.
I have a selectOneMenu in form 1:
<h:form id="form1" rendered="#">
<p:spacer height="30" />
<h:selectOneMenu id="oneMenu" value="#{bean.value}">
<f:selectItem itemLabel="Select Value" itemValue="" />
<f:selectItems id="itemValues"
value="#{bean.allItems}" var="allItems"
itemValue="#{allItems}" itemLabel="#{allItems.name}" />
</h:selectOneMenu>
and a DialogBOX in form2:
<h:form id="form2">
<p:dialog header="Create new Item" widgetVar="newItem"
resizable="false">
<h:panelGrid columns="2" style="margin-bottom:10px">
<h:outputLabel for="item" value="Itemname:" />
<p:inputText id="itemname" value="#{bean.itemName}" />
</h:panelGrid>
<p:commandButton value="Submit"
actionListener="#{bean.newItem}"
update="form1:oneMenu" oncomplete="newItem.hide();" />
</p:dialog>
I've tried update="form1:oneMenu" but it doesn't work. I've also read this post
but it doesn't work either.
Thanks for help.
Make sure to use update=":form1:myPanel".
Example :
<h:form id="form1">
<h:selectOneMenu id="oneMenu" value="#{bean.value}">
...
</h:selectOneMenu>
</h:form>
<h:form id="form2">
<p:dialog ..>
...
<p:commandButton value="Submit" update=":form1:oneMenu" ..../>
</p:dialog>
</h:form>
Otherwise
<h:form id="form1">
<p:selectOneMenu id="oneMenu" value="#{bean.value}">
...
</p:selectOneMenu>
</h:form>
<h:form id="form2">
<p:dialog ..>
...
<p:commandButton value="Submit" update=":form1:oneMenu" ..../>
</p:dialog>
</h:form>
Update For Comment : Try that below. You can use h:selectOneMenu or p:selectOneMenu.
<h:form id="form1">
<p:selectOneMenu style="width:195px;" required="true" id="cityMenu">
<f:selectItems value="#{SelectOneMenuBean.cities}"/>
</p:selectOneMenu>
<p:commandButton oncomplete="newItem.show()" value="Show Dialog"/>
</h:form>
<h:form id="form2">
<p:dialog header="Create new Item" widgetVar="newItem" resizable="false">
<h:panelGrid columns="2" style="margin-bottom:10px">
<h:outputLabel for="item" value="Itemname:" />
<p:inputText id="itemname" value="#{SelectOneMenuBean.selectedValue}" />
</h:panelGrid>
<p:commandButton value="Submit" update=":form1:cityMenu" oncomplete="newItem.hide();" />
</p:dialog>
</h:form>
public class SelectOneMenuBean {
private String selectedValue;
public String getSelectedValue() {
return selectedValue;
}
public void setSelectedValue(String selectedValue) {
this.selectedValue = selectedValue;
}
public String[] getCities() {
if(selectedValue != null && selectedValue.equals("AAA")) {
return new String[] {"City_1 of AAA", "City_2 of AAA", "City_3 of AAA"};
} else if(selectedValue != null && selectedValue.equals("BBB")) {
return new String[] {"City_1 of BBB", "City_2 of BBB", "City_3 of BBB"};
} else if(selectedValue != null && selectedValue.equals("CCC")) {
return new String[] {"City_1 of CCC", "City_2 of CCC", "City_3 of CCC"};
} else if(selectedValue != null && selectedValue.equals("DDD")) {
return new String[] {"City_1 of DDD", "City_2 of DDD", "City_3 of DDD"};
}
return new String[] {"No City"};
}
}
Note : If you input value AAA,BBB,CCC and DDD in dialog, the values of selectedOneMenu will be changed.
The following works but when create button is hit is clicked it commits a record with all null filds
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>New Movie</title>
<link rel="stylesheet" type="text/css" href="/diamondfilms.com.ar/faces/jsfcrud.css" />
</head>
<body>
<h:panelGroup id="messagePanel" layout="block">
<h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/>
</h:panelGroup>
<h1>New Movie</h1>
<h:form>
<h:inputHidden id="validateCreateField" validator="#{movie.validateCreate}" value="value"/>
<h:panelGrid columns="2">
<h:outputText value="Name:"/>
<h:inputText id="name" value="#{movie.movie.name}" title="Name" />
<h:outputText value="Sinopsis:"/>
<h:inputText id="sinopsis" value="#{movie.movie.sinopsis}" title="Sinopsis" />
<h:outputText value="Cast:"/>
<h:inputText id="cast" value="#{movie.movie.cast}" title="Cast" />
<h:outputText value="Trailer:"/>
<h:inputText id="trailer" value="#{movie.movie.trailer}" title="Trailer" />
<h:outputText value="Release:"/>
<h:selectOneRadio id="release" value="#{movie.movie.release}" title="Release">
<f:selectItem itemLabel="YES" itemValue="S" />
<f:selectItem itemLabel="NO" itemValue="N" />
</h:selectOneRadio>
<h:outputText value="Facebook Button:"/>
<h:inputText id="imagen6" value="#{movie.movie.facebookButton}" title="Image6" />
<h:form id="calendarForm2">
<h:outputLabel for="releaseDate" value="Date (MM/dd/yyyy HH:mm:ss): "/>
<t:inputCalendar id="releaseDate" monthYearRowClass="yearMonthHeader" weekRowClass="weekHeader" popupButtonStyleClass="standard_bold"
currentDayCellClass="currentDayCell" value="#{movie.movie.releaseDate}" renderAsPopup="true"
popupTodayString="Hoy :"
popupDateFormat="MM/dd/yyyy" popupWeekString="Semana :"
helpText="MM/DD/YYYY"
forceId="true">
<f:convertDateTime pattern="MM/dd/yyyy HH:mm:ss" />
</t:inputCalendar>
</h:form>
</h:panelGrid>
</h:form>
<h:form id="uploadForm1" enctype="multipart/form-data" >
<h:outputText value="Image1:"/>
<t:inputFileUpload id="file" value="#{movie.upLoad.upFile}" required="true" />
<h:commandButton value="Upload" action="#{movie.upLoadFile}" />
</h:form>
<h:form>
<br />
<h:commandLink action="#{movie.create}" value="Create"/>
<br />
<br />
<h:commandLink action="#{movie.listSetup}" value="Show All Movie Items" immediate="true"/>
<br />
<br />
<h:commandLink value="Index" action="welcome" immediate="true" />
</h:form>
</body>
</html>
where:
private MovieFacade jpaController = null;
#Resource
private UserTransaction utx = null;
public String create() {
try {
utx.begin();
} catch (Exception ex) {
}
try {
Exception transactionException = null;
jpaController.create(pelicula);
try {
utx.commit();
} catch (javax.transaction.RollbackException ex) {
transactionException = ex;
} catch (Exception ex) {
}
if (transactionException == null) {
JsfUtil.addSuccessMessage("Movie was successfully created.");
} else {
JsfUtil.ensureAddErrorMessage(transactionException, "A persistence error occurred.");
}
} catch (Exception e) {
try {
utx.rollback();
} catch (Exception ex) {
}
JsfUtil.ensureAddErrorMessage(e, "A persistence error occurred.");
return null;
}
return listSetup();
}
It even validates
Thank you very much!!
Your create button is not in the same form as the input values. You need to put the input of interest in the same form as the command link/button.
I have a custom EntityHome class. I wire the dependent entity in the wire method, but when I call the action (persist) the wired component is always null.
What could be the reason, similar code generated by seam gen is apparently working.
Here is the entity class.
The round.teeSet component is always null when persist is called, although it is shown in the jsf page.
Note: Seam version: 2.2.0.GA Jboss:
jboss-5.1.0.GA
I have overrden persist method to log the value of the wired element.
#Name("roundHome")
#Scope(ScopeType.CONVERSATION)
public class RoundHome extends EntityHome<Round>{
#In(required = false)
private Golfer currentGolfer;
#In(create = true)
private TeeSetHome teeSetHome;
#Override
public String persist() {
logger.info("Persist called");
if (null != getInstance().getTeeSet() ) {
logger.info("teeSet not null in persist");
} else {
logger.info("teeSet null in persist");
// wire();
}
String retVal = super.persist(); //To change body of overridden methods use File | Settings | File Templates.
return retVal;
}
#Logger
private Log logger;
public void wire() {
logger.info("wire called");
TeeSet teeSet = teeSetHome.getDefinedInstance();
if (null != teeSet) {
getInstance().setTeeSet(teeSet);
logger.info("Successfully wired the teeSet instance with color: " + teeSet.getColor());
}
}
public boolean isWired() {
logger.info("is wired called");
if(null == getInstance().getTeeSet()) {
logger.info("wired teeSet instance is null, the button will be disabled !");
return false;
}
else {
logger.info("wired teeSet instance is NOT null, the button will be enabled !");
logger.info("teeSet color: "+getInstance().getTeeSet().getColor());
return true;
}
}
#RequestParameter
public void setRoundId(Long id) {
super.setId(id);
}
#Override
protected Round createInstance() {
Round round = super.createInstance();
round.setGolfer(currentGolfer);
round.setDate(new java.sql.Date(System.currentTimeMillis()));
return round;
}
}
Here the xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE composition 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:s="http://jboss.com/products/seam/taglib"
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:a="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
template="layout/template.xhtml">
<ui:define name="body">
<h:form id="roundform">
<rich:panel>
<f:facet name="header>">
#{roundHome.managed ? 'Edit' : 'Add' } Round
</f:facet>
<s:decorate id="dateField" template="layout/edit.xhtml">
<ui:define name="label">Date:</ui:define>
<rich:calendar id="date" datePattern="dd/MM/yyyy" value="#{round.date}"/>
</s:decorate>
<s:decorate id="notesField" template="layout/edit.xhtml">
<ui:define name="label">Notes:</ui:define>
<h:inputTextarea id="notes" cols="80" rows="3" value="#{round.notes}" />
</s:decorate>
<s:decorate id="totalScoreField" template="layout/edit.xhtml">
<ui:define name="label">Total Score:</ui:define>
<h:inputText id="totalScore" value="#{round.totalScore}" />
</s:decorate>
<s:decorate id="weatherField" template="layout/edit.xhtml">
<ui:define name="label">Weather:</ui:define>
<h:selectOneMenu id="weather" value="#{round.weather}">
<s:selectItems var="_weather" value="#{weatherCategories}" label="#{_weather.label}"
noSelectionLabel=" Select " />
<s:convertEnum/>
</h:selectOneMenu>
</s:decorate>
<div style="clear: both;">
<span class="required">*</span> required fields
</div>
</rich:panel>
<div class="actionButtons">
<h:commandButton id="save" value="Save"
action="#{roundHome.persist}"
rendered="#{!roundHome.managed}" />
<!-- disabled="#{!roundHome.wired}" /> -->
<h:commandButton id="update" value="Update" action="#{roundHome.update}"
rendered="#{roundHome.managed}" />
<h:commandButton id="delete" value="Delete" action="#{roundHome.remove}"
rendered="#{roundHome.managed}" />
<s:button id="discard" value="Discard changes" propagation="end"
view="/Round.xhtml" rendered="#{roundHome.managed}" />
<s:button id="cancel" value="Cancel" propagation="end"
view="/#{empty roundFrom ? 'RoundList' : roundFrom}.xhtml"
rendered="#{!roundHome.managed}" />
</div>
<rich:tabPanel>
<rich:tab label="Tee Set">
<div class="association">
<h:outputText value="Tee set not selected" rendered="#{round.teeSet == null}" />
<rich:dataTable var="_teeSet" value="#{round.teeSet}" rendered="#{round.teeSet != null}">
<h:column>
<f:facet name="header">Course</f:facet>#{_teeSet.course.name}
</h:column>
<h:column>
<f:facet name="header">Color</f:facet>#{_teeSet.color}
</h:column>
<h:column>
<f:facet name="header">Position</f:facet>#{_teeSet.pos}
</h:column>
</rich:dataTable>
</div>
</rich:tab>
</rich:tabPanel>
</h:form>
</ui:define>
</ui:composition>
I suppose You have a single ScopeType.CONVERSATION (RoundHome) instance without any long-running conversation enabled. So you may have a Temporary conversation which survive until The render response phase.
When you submit your form, because you have a Temporary conversation, You just populate what you submit. It explains why your TeeSet is null. (Your submitted form does not contain any reference to a Tee instance)
If you really want your TeeSet survive until The next submit, you must enable a long-running conversation before showing and disable after submitting your form.
Just an advice: Each Home instance is by default ScopeType.CONVERSATION - inherited from Home. So you can set up your RoundHome as follows
#Name("roundHome")
public class RoundHome extends EntityHome<Round> {
...
}