Search code examples
jsfprimefacesactionlistenerviewparams

commandButton actionListener is not working in PrimeFaces page with viewParam


I found a weird behavior in JSF/PrimeFaces and ask your help to understand and get around it. The actionListener method in a commandButton is executed just once.

Contextualization:

I put a link in start page of my project to a second page, renderized as follows:

http://localhost:8080/MeusTestes-war/faces/somepage.xhtml?id=1

Notice there is a parameter sent by query string.

The somepage.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://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:p="http://primefaces.org/ui">
    <h:head>
        <title>Facelet Title</title>
    </h:head>

    <f:metadata>
        <f:viewParam name="id" value="#{someBean.id}" required="true" />
        <f:viewAction action="#{someBean.init}" />
    </f:metadata>

    <h:body>
        <h:form id="form1">
            <p:commandButton id="teste1" 
                             value="Teste" 
                             actionListener="#{someBean.doTeste}" />
        </h:form>
    </h:body>
</html>

As you can see, its extremely simple. Notice there is a metadata section doing the parameter reception and the execution of init() method. In page body there is a p:commandButton and a actionListener pointing to doTeste().

There is my Bean:

@Named(value = "someBean")
@ViewScoped
public class SomeBean implements Serializable {

    private int id;

    public SomeBean() {
    }

    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

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

    public void doTeste(ActionEvent actionEvent) {
        System.out.println("doTeste " + id);
    }

}

Well, now the mysterious behavior:

1) When page is loaded, as expected, the init() method shows a message with the correct property value got by viewParam. 2) Firing the button, as expected too, the doTeste() method shows a message with the correct property value. However, 3) Firing the button again, nothing happens!

Other facts:

If I remove the metadata section the doTeste() method is executed as many times as the button is clicked, which is supposed to happen. But the property, obviously, is not initialized.

If I switch the button definition from p:commandButton to h:commandButton, the doTeste() method is executed as expected AND the property is initialized. But I lose the PrimeFaces pattern.

My question:

How to do the commandButton actionListener from PrimeFaces behave the way is expected? (executing the method each time it is fired)

Thanks!


Solution

  • If you for testing purposes add a <p:growl id="msgs"/> and add update="msgs" to the button you'll see that validation fails on subsequent requests (because of required="true" on the viewParam).

    So you can either

    1. remove required="true". Probably a bad idea since you need it.
    2. add the parameter to the commandButton with <f:param name="id" value="#{someBean.id}"/>
    3. use OmniFaces <o:viewParam>.

    There is a more technical explanation here.