I have a dynamic accordion panel in my JSF 2.2 app that gets its values from a named bean. For example
<p:accordionPanel id="formsPanel" value="#{formController.forms}" var="form"
rendered="#{not empty formController.forms}">
<p:tab title="#{form.name}">
</p:tab>
</p:accordionPanel>
It is successfully listing all the tabs but the titles are blank.
I have another panel for adding forms to the list
<p:accordionPanel rendered="#{not empty formController.forms}">
<p:tab title="Add form">
<h:form id="addFormForm1">
<p:panelGrid columns="3" layout="grid">
<h:outputText value="Form name" />
<p:inputText value="#{formController.form.name}" />
<p:commandButton update="formsPanel" action="#{formController.createForm}"
value="Add form" />
</p:panelGrid>
</h:form>
</p:tab>
</p:accordionPanel>
The inputText should be setting the name of the form bean but it doesn't appear to be doing so
The code from my FormController
looks like so
@Named
@ViewScoped
public class FormController
{
private List<Form> forms;
@Inject
@Named("formService")
private CouchbaseFormService formService;
private Form form = new Form();
public void createForm()
{
try
{
formService.create(form);
} catch (CouchbaseServiceException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
form = new Form();
}
public Form getForm()
{
return form;
}
public void setForm(Form form)
{
this.form = form;
}
public List<Form> getForms()
{
return forms;
}
public void setForms(List<Form> forms)
{
this.forms = forms;
}
@PostConstruct
public void init()
{
try
{
forms = formService.findAll();
} catch (CouchbaseServiceException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
A form is a type of Widget
@Named
public class Widget
{
protected String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
//Other stuff
}
And the form as you can see nothing special
@Named
public class Form extends Widget
{
//Form related code
}
So with all of this, I don't see why <p:tab title="#{form.name}">
isn't showing me the name of the form in the title of the tab
I have also tried changing the name of the var in the accordion panel from form
to formInstance
but this didn't help, I've also removed @Named
from both the Form
class and Widget
class
If I start the server in debug mode and place a break point in the createForm method, I can see that the name of the FormController
form instance member is indeed null.
So why isn't <p:inputText value="#{formController.form.name}" />
setting the name of the form correctly?
EDIT:
I have managed to create a SSCCE
Here's the XHTML
<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Forms</title>
</h:head>
<h:body>
<p:accordionPanel id="formsPanel" value="#{formController.forms}"
var="formInstance" rendered="#{not empty formController.forms}">
<p:tab title="#{formInstance.name}">
</p:tab>
</p:accordionPanel>
<p:accordionPanel rendered="#{not empty formController.forms}">
<p:tab title="Add form">
<h:form id="addFormForm1">
<p:panelGrid columns="3" layout="grid">
<h:outputLabel value="Form name:" />
<p:inputText value="#{formController.form.name}" required="true"
label="text" />
<p:commandButton update="formsPanel"
action="#{formController.createForm}" value="Add form" />
</p:panelGrid>
</h:form>
</p:tab>
</p:accordionPanel>
</h:body>
</html>
Here's the FormService
, ignore the fact that this isn't how to do services, it's merely a means of demonstrating the issue.
@Named
public enum FormService
{
INSTANCE(new ArrayList<Form>());
private List<Form> forms;
private FormService(List<Form> forms)
{
this.forms = forms;
this.forms.add(new Form("Form 1"));
}
public void createForm(Form form)
{
forms.add(form);
}
public List<Form> findAll()
{
return forms;
}
}
The FormController
@Named
@ViewScoped
public class FormController
{
private FormService formService;
private List<Form> forms;
public Form form = new Form();
@PostConstruct
public void init()
{
formService = FormService.INSTANCE;
forms = formService.findAll();
}
public void createForm()
{
formService.createForm(form);
form = new Form();
}
public List<Form> getForms()
{
return forms;
}
public void setForms(List<Form> forms)
{
this.forms = forms;
}
public Form getForm()
{
return form;
}
public void setForm(Form form)
{
this.form = form;
}
}
And the Form
public class Form
{
private String name;
public Form()
{
}
public Form(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
As you can see in the screenshot below the initial form that it is initialised with appears ok, but adding a form with a name just renders a new tab without a title
What I've done is place a couple of break points one in the Form.setName and one in FormController.createForm.
When typing in a name of a form and clicking Add Form, both of these methods are called.
First of all setForm is called with a Form object reference (for example) com.test.Form@30998fa6 and it's name is correct.
Then createForm is called with a Form object reference com.test.Form@2ad84d0f and the name is null. What I don't get is why these are apparently two different form objects.
Another symptom is the @PostConstruct being called multiple times instead of just once.