如何在JSF中使用jsf.ajax.request手动发送ajax请求

5

我有一个表格,每一行都配置了“onclick”来调用一个js函数 - 这部分可以工作。我希望该函数向某个我可以自定义的方法发出ajax请求。返回后,应该呈现在表格下面的一个div中。这可行吗?我尝试使用以下代码编写JS函数:

<h:outputScript library="javax.faces" name="jsf.js" />
...
function clickAndRender() {
  jsf.ajax.request(this, event, {render: 'div-to-render'})
}

当然,这并没有起作用。我不知道“源”参数的值应该是什么(上面的代码使用了“this”),也不知道最后一个参数中的执行内容应该设置为什么。我还不知道如何定义要调用的url和“动作”方法。

解决方案也可以是在页面的其他地方使用某些不可见的表单,在点击时提交该表单。有人能帮忙吗?

3个回答

12
根据JSF 2.3规范,您可以使用<h:commandScript>来实现此操作。请参见规范问题613
<h:form>
    <h:commandScript name="foo" action="#{bean.action}" render="div-to-render" />
</h:form>
function clickAndRender() {
    foo();
}
Mojarra 2.3.0-m06 开始可用。

此答案已在问题发布三年后以上述方式更新。以下为原来的回答,当时还不存在<h:commandScript>


我不知道'source'参数(上面的代码使用'this')应该设置成什么值。

它应该是要调用的 UICommand 组件的客户端 ID,例如标准 JSF API 提供的 <h:commandLink><h:commandButton> 等。这样,在应用请求值阶段期间,JSF 将能够在组件树中定位所需的组件,然后将所有已注册的操作(监听器)排队执行。


我也不知道最后一个参数中的 execute 应该设置为什么。

它应该是要在表单提交期间处理的组件的以空格分隔的客户端 ID。它与您通常在 <f:ajax execute> 中使用的完全相同。


我也不知道如何定义要调用的 URL。

只是当前页面,由 <h:form> 生成的 <form> 衍生而来。但您不需要在 jsf.ajax.request() 中指定它。基于 UICommand 组件的客户端 ID,jsf.js 已经确定了它。


'action' 方法应该怎么定义。

只需像通常那样指定目标 UICommand 组件的 actionactionListener 属性。


总之,您具体的问题可能是视图中没有任何 UICommand 组件,因此无法使用 jsf.ajax.request()。一种方法是使用一个带有命令组件的表单,并通过 CSS display:none 将其隐藏:

<h:form id="foo" style="display:none">
    <h:commandLink id="bar" action="#{bean.method}" />
</h:form>

然后您可以将foo:bar用作source参数。

jsf.ajax.request('foo:bar', null, {'javax.faces.behavior.event': 'action', 'execute': '@form', 'render': 'div-to-render'});

在命令组件中,以上代码与<f:ajax execute="@form" render="div-to-render">的效果相同。您还可以选择这种方法,然后使用document.getElementById("foo:bar").click()而不是jsf.ajax.request()

或者,您也可以创建一个自定义的UICommand组件,使JavaScript用户更容易使用它们。JSF实用程序库OmniFaces具有这样的组件,即<o:commandScript>。请参见其展示页面源代码。JSF组件库PrimeFaces也有一个类似的组件,名为<p:remoteCommand>。请参见其展示页面RichFaces有一个<a4j:jsFunction>,其功能与前两者相同。请参见其展示页面


很遗憾,它不起作用。在Chrome中,我收到以下消息:未捕获的clientError:无法确定Sourceform,因为元素未附加到表单或我们具有相同标识符或名称的命名元素的多个表单,停止ajax处理jsf.js:8352 _MF_SINGLTN._getForm jsf.js:8352 _MF_SINGLTN.request jsf.js:8264 request jsf.js:8947 signatureClicked onclick 我尝试了显式调用jsf.ajax.request的方法。 - wujek
它可以与$("#foo\:bar").click()一起使用(我正在使用jquery)。如果您有时间,我很想了解第一种方法的问题在哪里。谢谢您的帮助! - wujek
1
不用客气。关于你最初的问题,你似乎在使用RichFaces命令组件(该错误消息是特定于RichFaces的)。抱歉,如果没有看到SSCCE,我无法回答那部分。我只能告诉你应该只使用<a4j:jsFunction>而不需要那个丑陋的jsf.ajax.request或jQuery解决方法 :) - BalusC
我设法创建了一个SSCCE;d,但它不起作用。最初的错误是由于在<table>中嵌套<h:form>引起的,在非ajax请求中工作得很好。现在我得到了一个更奇怪的错误-我看到服务器代码被调用,我看到它是Ajax,我看到值被设置了,但然后我在浏览器中得到一个对话框,上面写着: 错误消息:无法设置未定义的属性“name” 错误名称:clientError 服务器错误名称:TypeError 请注意,只有在项目阶段为开发阶段且没有注册其他错误侦听器时才会发送此消息。 您希望我如何使项目对您可用? - wujek
我也试过使用a4j:jsFunction,但失败了。函数已经生成,服务器也被调用了,但面板没有重新渲染。 - wujek

0

仅使用原生JSF,我不知道如何做到这一点。但是,你应该看一下PrimeFace的RemoteCommand。这正是你目前需要的。它可能是这样的:

<p:remoteCommand name="onRowClick" actionListener="myBean.onRowClick" update="div-to-render" />

<h:someComponent onclick="onRowClick" />

0

好的,我成功地实现了我需要的功能,使用了BalusC建议的所有方法,其中<a4j:jsFunction>是最好的选择。我写这篇跟进文章的原因是,刚开始我没有在问题中包含更多错误,并且评论空间不足 ;d

  1. 我的表单放错位置了 - 它被放在了“table”内:

    <table>
      <ui:repeat>...</ui:repeat>
      <form>...</form>
    </table>
    

    虽然对于非 Ajax 请求有效,但对于 Ajax 请求无效。将其移动到表格下方会导致请求被提交。

  2. 我想要呈现的面板最初是 rendered='false',这导致 HTML 标记首先不被输出。当 Ajax 调用返回时,它找不到我想要呈现的元素,并导致错误对话框或根本没有任何东西(取决于方法)。解决方案是使用一个始终呈现的具有相关 id 的包装器 div,并仅在该 div 内使用条件呈现。所以,不是这样做:

    <h:outputText id="to-render" rendered="${bean.clicked != null}">
      ...
    </h:outputText>
    

    我需要这样做:

    <h:panelGroup layout="block" id="to-render">
      <h:outputText rendered="${bean.clicked != null}">
        ...
      </h:outputText>
    </h:panelGroup>
    

非常感谢所有的帮助。我将把BalusC的帖子作为正确答案留下,因为它确实是正确的,而我的错误影响了整个过程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接