2
votes

I have this simple facelets page:

<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
    <title>Index</title>
</h:head>
<h:body>
    <h:form>
        <h:inputText id="firstname" value="#{fooBar.firstname}">
            <f:ajax event="keyup" render="echo" execute="myCommandButton"/>
        </h:inputText>
        <h:commandButton value="Submit" action="#{fooBar.fooBarAction()}" id="myCommandButton"/>
    </h:form>
    <br/>
    <h:outputText id="echo" value="#{fooBar.firstname}"/>
</h:body>
</html>

and the Foobar bean is as follows:

@ManagedBean
@ApplicationScoped
public class FooBar {

    private String firstname;

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getFirstname() {
        return firstname;
    }

    public void fooBarAction() {
        System.out.println("Foo bar action being executed!!!");
    }
}

So my expectation is to see the text Foo bar action being executed whenever I type something in the inputText field, but it is not the case. What am I missing?

Edit: Why am I expecting this behavior? I am studying the book Core JavaServer Faces and in the book it is noted that:

JSF 2.0 splits the JSF life cycle into two parts: execute and render.

Execute consists of: Restore View -> Apply Request Values -> Process Validations -> Update Model Values -> Invoke Application

When JSF executes a component on the server, it:

-Converts and validates the component 's value (if the component is an input).

-Pushes valid input values to the model (if the component is wired to a bean property).

-Executes actions and action listeners (if the component is an action).

So here, myCommandButton should be executed, isn 't it? And execution of a component means its action to be executed?

Edit #2

This quotation is from JavaServer Faces Complete Reference

If listener is not specified, the only action that will be invoked during the Invoke Application phase will be the one that corresponds to an ActionSource component listed in the execute attribute.

So as far as I understand, in my example, I have a component that implements the ActionSource interface (myCommandButton), and the action attribute of this component should be executed. But it is not?

2
@BalusC I read that answer but I could not find where you explain why action attribute of the executed component is not called?Koray Tugay
@BalusC There is no execute attribute in h:commandButton as well? I am not sure if that answer is relavent to my question.Koray Tugay
Hi @BalusC , please see my edit?Koray Tugay

2 Answers

6
votes

The execute attribute of <f:ajax> basically tells JSF which components to process through the JSF lifecycle during the postback. I.e. it basically tells JSF for which components it must execute the apply request values, process validations, update model values and invoke application phases. The apply request values phase will collect (decode) submitted HTML form (input and button) values. The validations phase will run conversion/validation on submitted values. The update model values phase will set submitted/converted/validated values in backing bean. The invoke application phase will execute the submitted action. Note that the key is that JSF will do this all based on submitted HTML form values.

In other words, the execute attribute is entirely server side. It is not client side as you seemed to expect. You seemed to expect that it tells the webbrowser to submit the specified component, as if you were clicking on it. This is not true. The button value is only processed through the JSF lifecycle when it was actually being pressed/clicked/submitted.

If the button is specified in execute attribute and JSF determines during processing the lifecycle that the button value is actually not submitted (i.e. it is entirely absent in HTTP request parameter map), then JSF won't queue the action event during apply request values phase at all. And therefore nothing will be invoked during invoke application phase.

When the <f:ajax> event is triggered, it's actually the enclosing component which is the action source. You should therefore hook the desired action listeners on it. You can use listener attribute of <f:ajax> for that.

<h:form>
    <h:inputText id="firstname" value="#{fooBar.firstname}">
        <f:ajax event="keyup" listener="#{fooBar.keyupListener}" render="echo" />
    </h:inputText>
    <h:commandButton value="Submit" action="#{fooBar.fooBarAction}" id="myCommandButton"/>
</h:form>

@ManagedBean
@RequestScoped
public class FooBar {

    private String firstname;

    public void keyupListener() {
        System.out.println("Keyup listener being executed");
    }

    public void fooBarAction() {
        System.out.println("Foo bar action being executed");
    }

    // ...
}

See also:

1
votes

The action and/or actionListener you want to call on each key stroke have to be defined in the f:ajax facet. You defined your action in the h:commandButton below. JSF doesn't see any connection between the ajax facet and the button. Apart from technical reasons, there are at least two reasons making this behaviour plausible:

  • You can have multiple command buttons in your form. In fact, more often than not you have at least two: "save" and "cancel". Should both actions be triggered on every key stroke? In which order? There's no way to decide that automatically, so JSF decides to avoid this problem by forcing you to define the action within the AJAX facet. Mind you: Your form might contain a table consisting of 100 rows, each with a "delete", "edit", and "insert new row after this row" button. Which action should be executed?
  • The input field may have multiple f:ajax facets. For example, you can define different facets for the events "keyup" and "blur". If you define multiple facets, you probably want them to call different backend bean methods. You do not want them to call any other command button of the form. Remember, it might be the "cancel" button, which is a bit inconvenient if it's triggered on each key stroke.

So the statement you've quoted from the Core JSF book is correct. Every action and actionListener is executed. Your mistake is that you've mentally expanded the scope to the entire form. Instead, JSF only looks at the component surrounding the AJAX facet.

The quotation of the JavaServer Faces Complete Reference simply sounds wrong to me. When neither an action nor an actionListener is specified, the "invoke application" phase of JSF doesn't do anything. The input is sent to the server, it is validated, it is stored in the backend bean and it's used to render the page again. But no action is called because you didn't specify an action to be called.