JSF Ajax Invoke Application 没有被执行?

JSF Ajax Invoke Application is not executed?

我有这个简单的 facelets 页面:

<!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>

Foobar bean如下:

@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!!!");
    }
}

所以我的期望是每当我在 inputText 字段中键入内容时看到正在执行的文本 Foo 栏操作,但它是不是这样的。我错过了什么?

编辑:为什么我会期待这种行为? 我正在研究这本书 Core JavaServer Faces 并且在书中指出:

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).

所以在这里,myCommandButton 应该被执行,不是吗?组件的执行意味着它的动作被执行?

编辑#2

此引文来自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.

所以据我了解,在我的例子中,我有一个组件实现了ActionSource接口(myCommandButton),应该执行这个组件的action属性。但不是吗?

您要在每次击键时调用的动作 and/or actionListener 必须在 f:ajax 方面定义。您在下面的 h:commandButton 中定义了您的操作。 JSF 看不到 ajax 方面和按钮之间的任何连接。除了技术原因外,至少有两个原因使这种行为看似合理:

  • 您的表单中可以有多个命令按钮。事实上,通常您至少有两个:"save" 和 "cancel"。是否应该在每次击键时触发这两个动作?按什么顺序?没有办法自动决定,所以 JSF 决定通过强制您在 AJAX 方面定义操作来避免这个问题。请注意:您的表单可能包含一个由 100 行组成的 table,每行有一个 "delete"、"edit" 和 "insert new row after this row" 按钮。应该执行哪个动作?
  • 输入字段可能有多个 f:ajax 方面。例如,您可以为事件 "keyup" 和 "blur" 定义不同的方面。如果您定义多个方面,您可能希望它们调用不同的后端 bean 方法。您不希望他们调用窗体的任何其他命令按钮。请记住,它可能是 "cancel" 按钮,如果它在每次击键时触发,会有点不方便。

所以您从 Core JSF 书中引用的陈述是正确的。每个 action 和 actionListener 都被执行。你的错误是你已经在心理上将范围扩大到整个表格。相反,JSF 只查看围绕 AJAX 方面的组件。

JavaServer Faces Complete Reference 的引用对我来说简直是错误的。当既未指定动作也未指定 actionListener 时,JSF 的 "invoke application" 阶段不执行任何操作。输入被发送到服务器,经过验证,存储在后端 bean 中,并用于再次呈现页面。但是没有调用任何操作,因为您没有指定要调用的操作。

<f:ajax>execute 属性基本上告诉 JSF 在回发期间通过 JSF 生命周期处理哪些组件。 IE。它基本上告诉 JSF 它必须为哪些组件执行应用请求值、处理验证、更新模型值和调用应用程序阶段。应用请求值阶段将收集(解码)提交的 HTML 表单(输入和按钮)值。验证阶段将 运行 conversion/validation 提交的值。更新模型值阶段将在支持 bean 中设置 submitted/converted/validated 值。调用应用程序阶段将执行提交的操作。请注意,关键是 JSF 将根据 submitted HTML 表单值来完成这一切。

换句话说,execute属性完全是服务器端的。它不是您所期望的客户端。您似乎期望它告诉网络浏览器提交指定的组件,就好像您正在单击它一样。这不是真的。按钮值仅在 实际上 为 pressed/clicked/submitted.

时通过 JSF 生命周期进行处理

如果在 execute 属性中指定了按钮,并且 JSF 在处理生命周期期间确定实际上未提交按钮值(即它在 HTTP 请求参数映射中完全不存在),则 JSF 不会完全在应用请求值阶段对操作事件进行排队。因此在调用应用程序阶段不会调用任何东西。

<f:ajax>事件被触发时,它实际上是作为动作源的封闭组件。因此,您应该在其上挂钩所需的动作侦听器。您可以为此使用 <f:ajax>listener 属性。

<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");
    }

    // ...
}

另请参阅:

  • Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
  • How does JSF process action listener?