2

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?

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319

2 Answers2

6

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:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thank you for your response and the time you take. But my understanding from JavaServer Faces Complete Reference that I quoted in my question is still leads me to expect the buttons Action attribute to be executed. I think this behavior is bit weird. In my example, does nothing at all happens because of "execute="myCommandButton""? It has no use at all? If the CommandButton had Validators, would they be called? – Koray Tugay Jul 06 '16 at 13:11
  • Nothing happens because you didn't physically click the button. – BalusC Jul 06 '16 at 13:12
  • Do you know any examples for good uses of execute attribute of f:ajax event. I am not sure how it can be made useful. – Koray Tugay Jul 06 '16 at 13:13
  • Check the 1st "See also" link and substitute "process" as "execute". – BalusC Jul 06 '16 at 13:13
  • If I enclose the form itself in instead of, execute="myCommandButton" would work as I expected, no? – Koray Tugay Jul 06 '16 at 13:19
  • It will only work "as expected" when you physically click the button. But, much better is to just declare the desired backing bean method in `listener` attribute of ``, as answered. If it's after all actually exactly the same method as you'd like to invoke in the submit button, then you've a design problem. – BalusC Jul 06 '16 at 13:36
  • I think the main reason is that f:ajax ignores the action attributes of the components to be executed.. – Koray Tugay Jul 06 '16 at 14:03
  • No, as answered, the reason is because the component of interest is not submitted. You didn't physically press/click/invoke the button in client. So its value is not submitted from client to server. So JSF won't even consider to process/execute the associated component in server side. The `execute` attribute represents client IDs of components whose **submitted values** must be processed during executing the JSF lifecycle. – BalusC Jul 06 '16 at 14:04
1

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.

Stephan Rauh
  • 3,069
  • 2
  • 18
  • 37
  • I was expecting that the commandButton would be "executed" where "execute" phase includes triggering the Action of the component. Clearly, this is not the case. – Koray Tugay Jul 04 '16 at 16:26
  • Can you comment on the statement from JavaServer Faces Complete Reference, which is in Edit #2 of my question? – Koray Tugay Jul 04 '16 at 16:39
  • I already commented on the quote in edit #2. I thinks it's nonsense. Probably the authors wanted to express something else. Mind you, as BalusC says in his answer, the `execute` attribute defines which attributes are sent to the server. IMHO, that's a silly name, and that's why both PrimeFaces and BootsFaces rename it to `process` (it determines which input fields are processed by the server). – Stephan Rauh Jul 05 '16 at 18:35