0

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

enter image description here

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.

PDStat
  • 5,513
  • 10
  • 51
  • 86
  • 1
    I think you have a name clash. The var is 'form' but that is at the same time name of a managed cdi bean due to the `@Named` annotation. The latter is most likely not needed if you access the forms from a List
    .
    – Kukeltje Dec 04 '15 at 11:22
  • Tried renaming the var to `formInstance` but it didn't work – PDStat Dec 04 '15 at 12:55
  • Nonetheless, get rid of `@Named` from entity classes. It doesn't belong there. – BalusC Dec 04 '15 at 13:07
  • Did you also rename it in the tab title? I hope you did – Kukeltje Dec 04 '15 at 13:24
  • I have yes, I've also now removed `@Named` from the Form class – PDStat Dec 04 '15 at 13:30
  • This is not an sscce. The widget is not needed, one property is enough, the service is not needed and read about injecting beans (the service) into other beans. Your usage of the FormService is like I have not seen anywhere… – Kukeltje Dec 04 '15 at 18:45
  • Thanks I am aware injecting beans this was merely me trying to get something demonstrable hence the FormService as you see it here. Point taken about the widget, I have edited the above. – PDStat Dec 04 '15 at 18:56
  • Is it feasible to have one form inside the body and have your commandButton update `@form instead of formsPanel – Mahendran Ayyarsamy Kandiar Dec 05 '15 at 20:23
  • @MahendranAyyarsamyKandiar Also tried that with no luck – PDStat Dec 07 '15 at 07:44

2 Answers2

2

When you use javax.faces.bean.ViewScoped use '@ManagedBean. When you use import javax.faces.view.ViewScoped use '@Named as mentioned here https://jsflive.wordpress.com/2013/07/17/jsf22-cdi-view-scope/

0

OK after a bit more digging I've found an answer. This helped

https://stackoverflow.com/a/14813093/564045

When I switched to using @ManagedBean it started working. What I'm not sure of is I am using Glassfish 4 and I have the following dependency in my POM

    <dependency>
        <groupId>javax.faces</groupId>
        <artifactId>javax.faces-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>

So I was under the impression I am using JSF 2.2, so why isn't this working with @Named

Community
  • 1
  • 1
PDStat
  • 5,513
  • 10
  • 51
  • 86
  • It depends if you had import javax.faces.bean.ViewScoped or import javax.faces.view.ViewScoped. Also if you had all CDI jars in classpath – Mahendran Ayyarsamy Kandiar Dec 07 '15 at 15:01
  • This is not a solution to your real problem, but since your question is still not [mcve] it is hard to find the cause. And `@Named` is CDI not JSF. if @Named did not work you must have gotten lots of different errors, so I think it was working... – Kukeltje Dec 07 '15 at 16:50
  • @Kukeltje, you know what, knock yourself out. It is verifiable https://paulstat@bitbucket.org/paulstat/test-jsf.git – PDStat Dec 07 '15 at 21:50
  • @Mahendran it was a faces bean. Also using glassfish where weld cdi dependencies are provided – PDStat Dec 07 '15 at 22:07
  • 2
    @PaulStatham I think thats the reason it did not work. When you use javax.faces.bean.ViewScoped use '@ManagedBean. When you use import javax.faces.view.ViewScoped use '@Named as mentioned here https://jsflive.wordpress.com/2013/07/17/jsf22-cdi-view-scope/ – Mahendran Ayyarsamy Kandiar Dec 07 '15 at 22:28
  • Thank you I shall give that a go – PDStat Dec 07 '15 at 22:34
  • I don't care about just verifyable, its about minimal to… and complete… – Kukeltje Dec 07 '15 at 22:56
  • @MahendranAyyarsamyKandiar add that as an answer and I'd be happy to accept it – PDStat Dec 08 '15 at 07:47