i have these simple pages:
list.xhtml
<h:form id="form">
<h:dataTable value="#{testBean.model}" var="elem">
<h:column>
<f:facet name="header">code</f:facet>
#{elem.code}
</h:column>
<h:column>
<f:facet name="header">description</f:facet>
#{elem.description}
</h:column>
<h:column>
<f:facet name="header">action</f:facet>
<h:commandButton action="#{testBean.edit(elem)}" value="edit"/>
</h:column>
</h:dataTable>
</h:form>
edit.xhtml
<h:form id="form">
<h:panelGrid columns="2">
<h:outputLabel value="code"/>
<h:inputText value="#{testBean.selection.code}"/>
<h:outputLabel value="description"/>
<h:inputText value="#{testBean.selection.description}"/>
</h:panelGrid>
<h:commandButton action="#{testBean.update}" value="update"/>
</h:form>
and this bean:
@ManagedBean
public class TestBean implements Serializable
{
private static final long serialVersionUID = 1L;
@EJB
private PersistenceService service;
private Object selection;
private List<UnitType> model;
@PostConstruct
public void init()
{
model = service.findAll(UnitType.class);
}
public String edit(Object object)
{
System.out.println(Tracer.current(object));
setSelection(object);
return "edit";
}
public String update()
{
System.out.println(Tracer.current(selection));
return "list";
}
// getters and setters
}
so the table is rendered, when i click one of the "edit" buttons it navigates to "edit.jsf" showing filled input, but when i click the "update" buttons it gives me this error:
javax.el.PropertyNotFoundException: /test2/edit.xhtml @27,54 value="#{testBean.selection.code}": Target Unreachable, 'null' returned null
note that i know how to implement a @ViewScoped interface to manage CRUD operations, but this is a simple proof of concept that i need to better understand JSF lifecycle.
so i want "testBean" to be @RequestScoped
UPDATE trying with f:viewParam
, still not understanding...
list.xhtml
<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>test list</title>
</h:head>
<h:body>
<h:messages/>
<h:form id="form">
<h:dataTable value="#{testBean2.model}" rows="10" var="elem">
<h:column>
<f:facet name="header">converterString</f:facet>
#{elem.converterString}
</h:column>
<h:column>
<f:facet name="header">first name</f:facet>
#{elem.firstName}
</h:column>
<h:column>
<f:facet name="header">last name</f:facet>
#{elem.lastName}
</h:column>
<h:column>
<f:facet name="header">action</f:facet>
<h:commandButton action="#{testBean2.edit}" value="edit">
<f:param name="entity" value="#{elem.converterString}"/>
</h:commandButton>
<h:commandButton action="#{testBean2.edit2}" value="edit2">
<f:param name="entity" value="#{elem.converterString}"/>
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
edit.xhtml
<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<f:metadata>
<f:viewParam id="entityParam" name="entity" value="#{testBean2.selection}" converter="entityConverter" required="true"/>
</f:metadata>
<h:head>
<title>test edit</title>
</h:head>
<h:body>
<h:messages/>
<h:form id="form">
<h:panelGrid columns="2">
<h:outputLabel value="selection"/>
<h:outputText value="#{testBean2.selection.converterString}"/>
<h:outputLabel value="firstName"/>
<h:inputText value="#{testBean2.selection.firstName}"/>
<h:outputLabel value="lastName"/>
<h:inputText value="#{testBean2.selection.lastName}"/>
</h:panelGrid>
<h:commandButton action="#{testBean2.update}" value="update" ajax="false">
<f:param name="entity" value="#{testBean2.selection.converterString}"/>
</h:commandButton>
</h:form>
</h:body>
</html>
testBean2.java
@ManagedBean
public class TestBean2 implements Serializable
{
private static final long serialVersionUID = 1L;
@EJB
private PersistenceService service;
private Object selection;
private List<Person> model;
@PostConstruct
public void init()
{
Tracer.out();
model = service.queryAll(Person.class);
}
public String edit()
{
JsfUtils.addSuccessMessage("edited");
return "edit";
}
public String edit2()
{
JsfUtils.addSuccessMessage("edited");
return "edit?faces-redirect=true&includeViewParams=true";
}
public void update()
{
Tracer.out(selection);
JsfUtils.addSuccessMessage("updated");
}
// getters and setters
}
if i press "edit" button it goes to edit
page, but selection is null and no message is showed.
if i press "edit2" button it goes to edit
page, but selection is null, showing required message and the url is edit.jsf?entity=
what am i doing wrong?
Finally I found a way: data will be in a long scope, bean in short.
Note that this is just a proof of concept, not a real use case. And be aware, when dealing with @RequestScope
beans, of PrimeFaces lazy DataTable model scope
@ManagedBean
public class TestBean
{
@EJB
private PersistenceService service;
@ManagedProperty("#{viewScope.item}")
private Item item;
@ManagedProperty("#{sessionScope.model}")
private EntityDataModel<Item> model;
@PostConstruct
public void init()
{
if(model == null)
{
model = new EntityDataModel<Item>(Item.class);
Faces.setSessionAttribute("model", model);
}
}
public String update()
{
Faces.getFlash().setKeepMessages(true);
try
{
item = service.update(item);
Faces.setViewAttribute("item", item);
JsfUtils.addSuccessMessage("updated");
return "view?faces-redirect=true&includeViewParams=true";
}
catch(Exception e)
{
e.printStackTrace();
JsfUtils.addErrorMessage(e);
}
return null;
}
// getters and setters, other actions, ...
}
list.xhtml
<p:dataTable value="#{testBean.model}" var="elem" ...>
...
<p:column exportable="false" toggleable="false" headerText="#{bundle.actions}">
<!-- two techniques available for navigation -->
<p:button outcome="view?id=#{elem.converterString}" icon="#{icons.view}" />
<p:commandButton rendered="#{user.isEditAllowed(elem)}"
action="edit?faces-redirect=true&includeViewParams=true" process="@form"
icon="#{icons.edit}">
<f:param name="id" value="#{elem.converterString}" />
</p:commandButton>
</p:column>
</p:dataTable>
view.xhtml
<f:metadata>
<o:viewParam id="itemId" name="id" value="#{viewScope.item}" required="true"
converter="entityConverter" />
</f:metadata>
<ui:composition template="/WEB-INF/templates/template.xhtml">
<ui:define name="content">
<p:panelGrid columns="2">
<h:outputLabel value="#{bundle.name}" />
<h:outputText value="#{item.name}" />
...
</p:panelGrid>
<p:button outcome="list" value="#{bundle.list}" icon="#{icons.list}" />
<p:button rendered="#{user.isEditAllowed(item)}"
outcome="edit?id=#{item.converterString}" value="#{bundle.edit}"
icon="#{icons.edit}" />
</ui:define>
</ui:composition>
edit.xhtml
<f:metadata>
<o:viewParam id="itemId" name="id" value="#{viewScope.item}" required="true"
converter="entityConverter" />
</f:metadata>
<ui:composition template="/WEB-INF/templates/template.xhtml">
<ui:define name="content">
<p:panelGrid columns="2">
<h:outputLabel value="#{bundle.name}" />
<h:panelGroup>
<p:inputText id="name" value="#{item.name}" />
<p:message for="name" />
</h:panelGroup>
...
</p:panelGrid>
<p:commandButton process="@form" update="@form" action="#{testBean.update}"
value="#{bundle.update}" icon="#{icons.update}" />
<p:button outcome="view?id=#{item.converterString}" value="#{bundle.cancel}"
icon="#{icons.cancel}" />
</ui:define>
</ui:composition>