JSF Ajax Invoke Application未执行?

时间:2016-06-25 07:59:37

标签: ajax jsf jsf-2

我有这个简单的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 bar操作正在执行,但事实并非如此。我错过了什么?

编辑:为什么我期待这种行为? 我正在研究这本书Core JavaServer Faces,并在书中注意到:

  

JSF 2.0将JSF生命周期分为两部分:执行和呈现。

     

执行包括:恢复视图 - &gt;应用请求值 - &gt;处理   验证 - &gt;更新模型值 - &gt;调用应用程序

     

当JSF在服务器上执行组件时,它:

     

- 转换并验证组件的值(如果组件是输入)。

     

- 将有效输入值推送到模型(如果组件连接到bean属性)。

     

- 执行操作和操作侦听器(如果组件是操作)。

所以在这里,myCommandButton应该被执行,不是吗?并且组件的执行意味着要执行的操作?

编辑#2

此引用来自 JavaServer Faces完整参考

  

如果未指定侦听器,则将调用唯一的操作   在Invoke Application阶段期间将是对应的阶段   到execute属性中列出的ActionSource组件。

据我所知,在我的例子中,我有一个实现ActionSource接口(myCommandButton)的组件,并且应该执行该组件的action属性。但事实并非如此?

2 个答案:

答案 0 :(得分:5)

execute的{​​{1}}属性基本上告诉JSF在回发期间通过JSF生命周期处理哪些组件。即它基本上告诉JSF它必须执行哪些组件应用请求值,进程验证,更新模型值和调用应用程序阶段。应用请求值阶段将收集(解码)提交的HTML表单(输入和按钮)值。验证阶段将对提交的值运行转换/验证。更新模型值阶段将在backing bean中设置提交/转换/验证的值。调用应用程序阶段将执行提交的操作。请注意,关键是JSF将根据提交的 HTML表单值执行此操作。

换句话说,<f:ajax>属性完全是服务器端。正如您所期待的那样,它不是客户端。您似乎希望它告诉webbrowser提交指定的组件,就像您单击它一样。这不是真的。按钮值仅在实际被按下/单击/提交时通过JSF生命周期处理。

如果在execute属性中指定了按钮,并且JSF在处理生命周期期间确定按钮值实际上未提交(即在HTTP请求参数映射中完全没有),则JSF将不排队在申请请求值阶段期间的行动事件。因此,在调用应用程序阶段期间不会调用任何内容。

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

<f:ajax>

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

另见:

答案 1 :(得分:1)

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

  • 您可以在表单中使用多个命令按钮。事实上,你经常至少有两个:&#34; save&#34;和&#34;取消&#34;。是否应该在每次击键时触发两个动作?以什么顺序?由于无法自动决定,因此JSF决定通过强制您在AJAX方面定义操作来避免此问题。请注意:您的表单可能包含一个由100行组成的表,每行包含&#34;删除&#34;,&#34;编辑&#34;和&#34;在此行后插入新行&#34;按钮。应该执行哪个行动?
  • 输入字段可能有多个f:ajax方面。例如,您可以为事件定义不同的方面&#34; keyup&#34;和&#34;模糊&#34;。如果定义了多个方面,则可能希望它们调用不同的后端bean方法。您不希望它们调用表单的任何其他命令按钮。请记住,它可能是&#34;取消&#34;按钮,如果在每次击键时触发它会有点不方便。

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

JavaServer Faces Complete Reference的引用对我来说听起来不对。当既没有指定动作也没有指定actionListener时,&#34;调用应用程序&#34; JSF阶段没有做任何事情。输入被发送到服务器,它被验证,它存储在后端bean中,它用于再次呈现页面。但是没有调用任何动作,因为你没有指定要调用的动作。