JSF 2.0 AJAX:使用 jsf.ajax.request(或其他方式)从 javascript 调用 bean 方法

Posted

技术标签:

【中文标题】JSF 2.0 AJAX:使用 jsf.ajax.request(或其他方式)从 javascript 调用 bean 方法【英文标题】:JSF 2.0 AJAX: Call a bean method from javascript with jsf.ajax.request (or some other way) 【发布时间】:2011-04-12 06:33:59 【问题描述】:

一些背景知识:我正在构建一个自定义 JSF 组件。该组件基本上是一个文本编辑器,它应该有一个“保存”按钮,用于保存编辑器的内容字符串。当我使用CodeMirror 库时,我需要使用javascript 从编辑器中获取内容(字符串)并将其发送到服务器。因此,在这种情况下,我不能使用基于 XML 的 JS 调用,例如 f:ajax

问题:我打算用jsf.ajax.request 发送字符串,但它不直接支持在bean 上调用方法。如何以 AJAX 方式调用带有 JSF 的 bean 中的方法?

至少有两种方法可以解决这个问题:

在带有隐藏输入字段的页面中包含一个隐藏表单。从 javascript 更新该输入字段,然后调用 jsf.ajax.request 来发布该表单。如果需要,可以在属性的 getter 或 setter 中调用自定义操作。 使用原始的XMLHttpRequest(或者可能在其他一些 JS 库的帮助下)执行请求。创建一个 servlet 并调用它。

这两种方式都很笨拙,而且后者也超出了 JSF 的范围。

我错过了什么吗?你是怎么做到的?

有一个quite similar question,但给出的答案仅涉及基于 XML 的 AJAX 调用。还有another similar question,不过也指基于XML的AJAX调用。

【问题讨论】:

你是如何构建它的?作为UIComponent<ui:composition><composite:implementation>? 这个只是建立在ui:composition之上。基本上我在那里有一个textarea,我在script 元素中使用JS 调用进行初始化。我还有一个commandButton,它应该用作保存按钮。为什么,我使用复合组件还是 UIComponents 有关系吗? 使用UIComponent,您可以扩展UIInput,JSF 将负责更新模型值。但是再想一想,当涉及到基于 3rd 方 html/CSS/JS 的编辑器时,这当然很棘手。您是否考虑过一个完全值得的 JSF 组件?例如。 PrimeFaces p:editor. 扩展UIInput 的好点,但你可能是对的,在这种情况下这不是一个真正的选择。我快速搜索了现有组件,还找到了p:editor。不幸的是,现有的组件都不适合我们的需求,所以我不得不走这条路。 There is a way to call JSF Backing Bean method from Javascript 【参考方案1】:

我不知道如何使用 javascript 直接调用 bean,但这里有一个关于从 javascript 调用 f:ajax-declaration 的技巧:

1) 创建一个隐藏表单,其中包含要发送到服务器的所有数据的字段。也包括一个 h:commandButton:

<h:form id="hiddenForm" style="display: none;">
    <h:inputHidden id="someData" value="#someBean.someData" />
    <h:commandButton id="invisibleClickTarget">
        <f:ajax execute="@form" listener="#someBean.myCoolActionOnServer()" />
    </h:commandButton>
</h:form>

像往常一样,listener 属性,在本例中为#someBean.myCoolActionOnServer(),指的是您要在服务器上执行的方法。

2) 在其他一些按钮中,使用onclick 调用您的特殊 javascript 并通过 javascript 单击触发按钮:

<h:commandButton value="Click me" onclick="populateTheForm('hiddenForm'); document.getElementById('hiddenForm:invisibleClickTarget').click(); return false;" />

populateTheForm() 实际上应该将数据填充到 hiddenForm 的字段中。

这是对我的案例的简化,但应该可以。不过,仍在寻找更方便的方法。

【讨论】:

作为替代方案,您也可以不使用&lt;h:commandButton&gt; 并在&lt;h:inputHidden&gt; 中使用&lt;f:ajax&gt;,它会在change 事件上执行。那是更少的代码。 是的,如果用户只想转移一个字段(好吧,在这种情况下我愿意),这应该可以工作。如果表单中有多个字段,我猜这可能会触发不需要的行为,因为 AJAX 调用会在其余字段更新之前启动。 ...除非有人将f:ajax 用于最后更新的字段。是的,这可以解决问题。再次感谢您的建议,BalusC。 我尝试将f:ajax 直接放在h:inputHidden 中。结果是“ 无法将 附加到非 ClientBehaviorHolder 父级”。所以这是不可能的。 您的代码有一个小问题:您在打开 h:commandButton 的行中关闭它...【参考方案2】:

我做了好几次这个任务。哟不需要多重隐藏字段。您只能使用一个隐藏字段,通过 JSON.stringify 将所有输入值转换为 JSON 对象并设置到该字段中。在服务器端 - 将 JSON 对象(有许多 Java 库用于此)反序列化为 Java 类。就是这样。

【讨论】:

很高兴知道这一点,尽管您从中受益了什么?拥有多个字段 JSF 会自动进行转换/验证,您的代码更加静态类型化(尽管这种方法仍然很烂)。愿意敞开心扉吗?

以上是关于JSF 2.0 AJAX:使用 jsf.ajax.request(或其他方式)从 javascript 调用 bean 方法的主要内容,如果未能解决你的问题,请参考以下文章

JSF:AJAX 测试最佳实践

使用 JSF ajax 请求刷新 URL

jsf ajax 部分渲染

发出 JSF Ajax 请求时显示加载进度

JSF Ajax 渲染使用 Jquery Mobile 丢失 CSS

JSF ajax 请求中的异常处理