Search code examples
jsf-2primefaces

JSF viewAction passing param and it gets set, but returns to null


JSF 2.2
Primefaces 4.0
JBoss Wildfly

From a page with a list of customers, and want a button for each customer where the user can add items. When I click the "New Item" button I am redirected to the new item page.

In the url is the customer id

newItem.jsf;jsessionid=Xw7tdljr9f0atzyET2Fy6_WI?customerId=3

I can debug that the set customer id method in the new item bean in called with the value 3, nice :)
But right after I debug that the get customer id method is called.. and now the customer id is null :(

And I made a syso :

18:10:25,312 INFO [stdout] (default task-9) Setting customer id 3

So the customer id is begin set... but is reset to null somehow ????

customers.xhtml

<ui:define name="content">
<f:metadata>
    <f:viewParam name="customerId" value="#{customerController.customerEnt.id}" />
</f:metadata>
<h:form id="customers" prependId="false" includeViewParams="true">
    <p:dataTable id="dataTable" var="customer"
        value="#{customerController.customers}" rowKey="#{customer.id}"
        styleClass="userDataTableStyle" paginator="true" rows="10"
        selection="#{customerController.selectedCustomers}"
        paginatorTemplate="{CurrentPageReport}  {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
        lazy="true" rowsPerPageTemplate="10,15,50">
  ... 

        <p:column>
            <p:commandButton ajax="false" value="New Item" action="#{customerController.newItem(customer)}"/>
        </p:column>

    </p:dataTable>

</h:form>

newItem.xhtml

<ui:define name="content">
<f:metadata>
    <f:viewParam name="customerId"
        value="#{newItemController.customerId}" />
    <f:viewAction action="#{newItemController.init()}"/>
</f:metadata>
<h:form id="item" includeViewParams="true">
...

newItemController.java

@SuppressWarnings("serial")
@ViewScoped
@Named
public class NewItemController implements Serializable {

    private CustomerEnt customerEnt;
    private String customerId;

    @PostConstruct
    public void init() {
        itemEnt = new ItemEnt();

        if (customerId == null) {
            String message = "Bad request. Please use a link from within the system.";
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
            return;
        }

        customerEnt = customerDas.find(Long.parseLong(customerId));

        if (customerEnt == null) {
            String message = "Bad request. Unknown customer.";
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
        }
    }

    public String getCustomerId() {
        return customerId;
    }

    public void setCustomerId(String customerId) {
        this.customerId = customerId;
        System.out.println("Setting customer id " + customerId);
    }
}

CustomerController.java

@SuppressWarnings("serial")
@SessionScoped
@Named
public class CustomerController implements Serializable {

    private Long customerId;

    public String newItem(CustomerEnt customerEnt) {
        customerId = customerEnt.getId();
        return "newItem?faces-redirect=true&customerId=" + customerId;
    }

As L-Ray stated, the init was called twice, so I made this change in NewItemController:

        public void init() {
            System.out.println("In init");
        }

        @PostConstruct
        public void postConstruct() {
            itemEnt = new ItemEnt();
            System.out.println("In postConstruct");

        }

    public void loadData() {
            if (customerId == null) {
                String message = "Bad request. Please use a link from within the system.";
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
                return;
            }
        }


public void save() throws Exception {
        try {
            serviceSLSB.save(Long.parseLong(customerId), itemEnt);
            FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_INFO, "Saved!", "Item saved successful");
            facesContext.addMessage(null, m);
            postConstruct();
        } catch (ConstraintViolationException e) {
            itemEnt.setBid(null);
            String errorMessage = getRootErrorMessage(e);
            FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, "Saving unsuccessful");
            facesContext.addMessage(null, m);
        } catch (Exception e) {
            String errorMessage = getRootErrorMessage(e);
            FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, "Saving unsuccessful");
            facesContext.addMessage(null, m);
        }
    }

and in the newItem.xhtml

<f:metadata>
                <f:viewParam name="customerId"
                    value="#{newItemController.customerId}" />
                <f:viewAction action="#{newItemController.loadData()}"/>
            </f:metadata>

And now it works... :) but now I have a new problem.. i will create a separate question for that :) Thanks for the help


Solution

  • The given source looks good - just one thing caught my eyes: At the moment, your NewItemController.init() get's called twice

    • as @PostConstruct
    • through f:viewAction

    If you call the method anyway, you don't need the annotation, isn't it?