如何让 Richfaces 组件在按需加载的弹出窗口中工作?

Posted

技术标签:

【中文标题】如何让 Richfaces 组件在按需加载的弹出窗口中工作?【英文标题】:How to get Richfaces components to work in demand loaded popup? 【发布时间】:2013-12-28 00:25:36 【问题描述】:

在使用 RF 4 的单页 JSF 2.1 应用程序中,会有很多弹出窗口用于不同的表单来编辑数据。仅当单击 GUI 中的某个按钮时才应显示表单。由于我无法在原始页面加载时创建所有弹出窗口,包括内容和支持 bean,因此我使用延迟加载创建它们,类似于此问题中提出的第二个答案:Richfaces modalPanel load with Ajax

<a4j:outputPanel id="container">
    <c:if test="#popupController.isPopupVisible(popup.id)">
        <f:subview id="view">
            <rich:popupPanel id="popup" show="true" modal="false" autosized="true" resizeable="false" style="z-index:10000; background-color:#FFF;">
                <f:facet name="header">
                    <h:outputText value="#popup.title" />
                </f:facet>
                <f:facet name="controls">
                    <h:form id="closeButtonform">
                        <a4j:commandLink id="closePopup" render="container" action="#popupController.hidePopup(popup.id)" onbeforedomupdate="#rich:component('popup').hide(); return false;">X</a4j:commandLink>
                    </h:form>
                </f:facet>
                    <rich:extendedDataTable id="table" value="#itemBean.items" var="item">
                        ...
                    </rich:extendedDataTable>
            </rich:popupPanel>
        </f:subview>
    </c:if>
</a4j:outputPanel>
<h:form id="openButtonForm">
    <a4j:commandLink id="openPopup" render="container" action="#popupController.showPopup(popup.id)"  />
</h:form>

backing bean 不做任何魔术,只是存储数据,所以它们被忽略了。

目前的工作是打开和关闭显示/隐藏弹出窗口的弹出链接,并且仅在需要时创建包括弹出内容的支持 bean 在内的内容。我遇到的问题是弹出窗口内的组件(本示例中的 rich:extendedDataTable)已显示,但 JSF/Richfaces/Ajax 以某种方式未正确处理它们。让我进一步详细说明:当 c:if 测试在页面初始显示期间评估为 true 时,一切正常,javascript RichFaces.$('popup:view:table') 产生与表格关联的正确 RF JavaScript 对象。我可以随意关闭/打开弹出窗口,没有任何问题。但是,当页面加载时最初不存在弹出窗口然后使用按钮打开时,我收到以下 JS 错误。

Uncaught TypeError: Cannot call method 'addCSSText' of undefined popup.xhtml:1
(anonymous function) popup.xhtml:1
runScripts jsf.js.xhtml:1
doUpdate jsf.js.xhtml:1
response jsf.js.xhtml:1
richfaces.queue.response richfaces-queue.js.xhtml:413
jsf.ajax.response richfaces-queue.js.xhtml:50
onComplete jsf.js.xhtml:1
AjaxEngine.req.xmlReq.onreadystatechange jsf.js.xhtml:1

Uncaught TypeError: Cannot call method 'addLocale' of undefined popup.xhtml:1
(anonymous function) popup.xhtml:1
runScripts jsf.js.xhtml:1
doUpdate jsf.js.xhtml:1
response jsf.js.xhtml:1
richfaces.queue.response richfaces-queue.js.xhtml:413
jsf.ajax.response richfaces-queue.js.xhtml:50
onComplete jsf.js.xhtml:1
AjaxEngine.req.xmlReq.onreadystatechange jsf.js.xhtml:1

Uncaught TypeError: undefined is not a function popup.xhtml:1
(anonymous function) popup.xhtml:1
runScripts jsf.js.xhtml:1
doUpdate jsf.js.xhtml:1
response jsf.js.xhtml:1
richfaces.queue.response richfaces-queue.js.xhtml:413
jsf.ajax.response richfaces-queue.js.xhtml:50
onComplete jsf.js.xhtml:1
AjaxEngine.req.xmlReq.onreadystatechange

然后相同的 JavaScript RichFaces.$('popup:view:table') 产生 undefined 并且弹出窗口中的表格无法正确呈现。似乎所有依赖于 RF JavaScript(如列格式、滚动条等)的东西都没有初始化,在某些情况下也没有应用 CSS。在这里,我关闭/打开弹出窗口的频率也无关紧要,它总是坏掉。

有什么想法可以直接在 JSF 中或在打开按钮的 oncomplete 上的 JavaScript 中解决这个问题吗?

【问题讨论】:

虽然它可能不是问题的核心,但不要使用嵌套表单。如果您需要限制执行范围,请使用&lt;h:form&gt;,然后使用&lt;a4j:region&gt; 之类的内容。 谢谢@Makhiel,实际上我没有嵌套表单。我从我的代码中剥离了一点点。我现在修好了,看看&lt;a4j:region&gt; 是否适用于这种情况。 【参考方案1】:

问题是当一个组件被动态添加到 JSF 视图树时,它并没有正确加载该组件的资源依赖关系。

例如当rich:extendedDataTable 组件出现在树中时,JSF 从ExtendedDataTableRenderer 读取它的资源依赖关系,例如其中一个依赖关系是@ResourceDependency(library="org.richfaces", name = "extendedDataTable.js")target 定义默认为head,因此该资源作为子资源添加到h:head 在视图树中。

在我看来,JSF 检测此类添加并在 ajax 请求完成时加载新资源是合理的(RichFaces 3 ajax 引擎曾经这样做,但由于 JSF2/RichFaces4 JSF 承担了全部责任并实现了自己的 ajax 引擎) .但是 JSF 不会加载添加到头部的资源。

可能的解决方案/解决方法:

在初始页面加载时加载所有资源。 如果您启用资源打包,那么它将完成 - 将加载包含所有 RichFaces 资源的单个文件。对于您可能希望禁用打包(以便于调试)的开发环境,您可以在模板中添加以下技巧,以强制所有资源在初始页面加载时加载

.

  <c:if test="#initParam['javax.faces.PROJECT_STAGE'] eq 'Development'">
    <!-- Force pre-loading all the resources (js/css/etc) of the specified components as they may appear in JSF tree dynamically. -->
    <rich:extendedDataTable rendered="false"/>
    <!-- Other components go here. -->
  </c:if>
让 JSF 以某种方式加载更新后的h:head 的资源。这只是一个想法,但它可能会引导你去做一些事情。例如。如果你这样做render="@all" - 它的工作速度要慢得多,但会根据需要加载所有内容,也许有一种方法可以让 JSF 渲染头部区域。

【讨论】:

非常感谢,就是这样。

以上是关于如何让 Richfaces 组件在按需加载的弹出窗口中工作?的主要内容,如果未能解决你的问题,请参考以下文章

修复Extjs5.1.4的弹出窗(window)BUG

小谢第18问:如何让element-ui的弹出框每次显示的时候初始化,重新加载元素?

小谢第18问:如何让element-ui的弹出框每次显示的时候初始化,重新加载元素?

DuiVision开发教程(18)-弹出窗

window.open 里的resizable=no参数在火狐里无效!有啥方法在火狐里的弹出窗不能拖动大小吗?

如何在 android studio 的弹出窗口内添加滚动的 listView?