2

I am currently working on a project using Primefaces 4.0 and JEE 6. As a build-tool we use maven, and we got a JBoss Application Server.

So it was supposed to be simple. When a validation error occurs, I was supposed to prevent a tab-change in my view. Nothing big, but it needed to be done.

What happened next totally flabberghasted me, but first what I did:

  • Define a backing bean to handle the event.
  • Define a listener there.
  • Use <p:ajax /> to fire the tabChange event to my bean.

Well it was simple enough until there. When there were no validation errors, it worked just fine. Then I tried to validate the values in the view against my Model-Bean and was quickly stopped in my tracks.

As soon as I willingly produced errors in the View, to trigger the faces messages, the tabChange listener was not executed anymore. In fact, not even the @RequestScoped controller-class with the listener was constructed.

I proceeded to create a minimal working example with help of the Weld CDI maven archetype.

Now here I stand, at wits end and present to you my example:

home.xhtml:

I removed the surrounding xml-declaration and ui:define stuff, but that's what I took to reproduce it.

<h1>Hello World!</h1>
<p>
    Your CDI bean
    <code>HelloWorld</code>
    says <span style="color: blue;">#{helloWorld.text}</span> using the
    Unified EL.
</p>

<h:form id="bv">
    <h2>Bean Validation examples</h2>
    <p>Enforces annotation-based constraints defined on the model
        class.</p>
    <p:tabView id="tabView" effect="fade"
        effectDuration="normal">
        <p:ajax event="tabChange" update="tabView" listener="#{controller.tabChange}"/>
        <p:tab title="Tab 1">
            <table>
                <tr>
                    <th style="text-align: right;"><h:outputLabel for="letters"
                            value="Letters:" /></th>
                    <td><p:inputText id="letters" value="#{helloWorld.letters}" />
                        <p:message for="letters" errorClass="invalid" /></td>
                </tr>
            </table>
        </p:tab>
        <p:tab title="Tab 2">
            <p>Random text to be displayed</p>
        </p:tab>
    </p:tabView>
</h:form>

Controller.java:

here I only removed the package-declaration, for the protection of the innocent.

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

import org.primefaces.event.TabChangeEvent;

@Named
@RequestScoped
public class Controller implements Serializable {

    private static final long serialVersionUID = -1126987875831465303L;

    public Controller() {
    }

    @PostConstruct
    public void init() {
        System.out.println("Constructed " + this.getClass().getSimpleName());
    }

    public void tabChange(final TabChangeEvent event) {
        System.out.println("Listener was reached");
    }
}

Last but not least, the model-bean, slightly shortened from what the archetype provides:

HelloWorld.java:

Again I removed the namespace declaration.

import javax.annotation.PostConstruct;
import javax.enterprise.inject.Model;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

import org.hibernate.validator.constraints.NotEmpty;

public @Model
class HelloWorld {
    private final String text = "Hello World!";

    private String letters;

    public HelloWorld() {
    }

    @PostConstruct
    public void initialize() {
        System.out
                .println(this.getClass().getSimpleName() + " was constructed");

    }

    public String getText() {
        return text;
    }

    @NotNull
    @NotEmpty
    @Pattern(regexp = "[A-Za-z]*", message = "must contain only letters")
    public String getLetters() {
        return letters;
    }

    public void setLetters(final String letters) {
        this.letters = letters;
    }
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Vogel612
  • 5,620
  • 5
  • 48
  • 73

1 Answers1

3

It seems that the JSF lifecycle interferes with what I want to do.

Taken from this german webiste:

JSF Lifecycle

It seems, that the event listener will only get invoked in the "Invoke Application"-phase.
Assuming that, it becomes quite obvious, that after "Process Validations" we skip to "Render Response" and our whole backing bean gets ignored.

It is possible to circumvent this, using immediate="true", but upon realizing there is a way better solution to the underlying problem I used that on, namely <p:wizard /> instead, that does exactly what I want.

Vogel612
  • 5,620
  • 5
  • 48
  • 73