EL作为属性传递给数据表内的复合组件时未解析

Posted

技术标签:

【中文标题】EL作为属性传递给数据表内的复合组件时未解析【英文标题】:EL not resolved when passed as attribute to composite component inside datatable 【发布时间】:2020-03-29 03:37:22 【问题描述】:

我遇到了一个问题,即在复合组件的初始化时没有解决 EL 表达式。代码如下:

<p:column sortable="false" toggleable="false" >
    <div styleClass="panelActions">
    <div styleClass="btn_view_documents">
            <w:commandButton buttonType="text" value="#msg.lbl_quick_view"
                id="viewerDocument"
                isDefault="true"
                onclick="IB_#dataItemForIB.document.documentId_Viewer();"
                ajax="false">
                 <f:param name="documentId" value="#dataItemForIB.document.documentId"/>
                <tags:documentViewerLoader 
                    id="#'IB_'.concat(dataItemForIB.document.documentId).concat('_Viewer')"
                    documentId="#dataItemForIB.document.documentId" 
                    documentViewerId="DocViewer"
                    mainPanelId="XXXX"
                    processDocumentLoad="#SomeBean.someMethod()"
                 />
            </w:commandButton>

这是组件声明:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition 
xmlns="http://www.w3.org/1999/xhtml" 
xmlns:h="http://java.sun.com/jsf/html" 
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets" 
xmlns:c="http://java.sun.com/jsp/jstl/core" 
xmlns:p="http://primefaces.org/ui" 
xmlns:w="http://xxx.xxx.xxx/w/components"
xmlns:composite="http://java.sun.com/jsf/composite">

<composite:interface shortDescription="Callable command for load document">
    <composite:attribute name="id" default="defaultDocumentLoader"/>
    <composite:attribute name="documentId" type="java.lang.String"/>
    <composite:attribute name="documentViewerId" type="java.lang.String"/>
    <composite:attribute name="mainPanelId" type="java.lang.String"/>
    <composite:attribute name="isCrop" type="java.lang.String" default="false"/>
    <composite:attribute name="processDocumentLoad" method-signature="void action()"/>
</composite:interface>

<composite:implementation>
    <script>
        #cc.attrs.id = function()
            DocViewer_quickViewCached(
                    '#cc.attrs.id',
                    '#view.locale.language', 
                    '#cc.attrs.mainPanelId', 
                    '#cc.attrs.documentId',
                    '#cc.attrs.isCrop');
        
    </script>
    
    <p:commandButton 
        style="display:none" 
        action="#cc.attrs.processDocumentLoad" 
        ajax="true" 
        oncomplete="DocViewer_quickViewNoCached('#cc.attrs.id','#view.locale.language', '# 
cc.attrs.documentId', '#cc.attrs.mainPanelId', '#cc.attrs.isCrop', xhr, status,args)" 
        widgetVar="#cc.attrs.id_documentLoadInvocator">
        <f:param name="id" value="#cc.attrs.id"/>
        <f:param name="documentId" value="#cc.attrs.documentId"/>
    </p:commandButton>
</composite:implementation>

这是 HTML 输出:

<script>
    IB__Viewer = function()
        DocViewer_quickViewCached(
                'IB__Viewer',
                'en', 
                'XXXX', 
                'id00000001336875',
                'false');
    
</script>
        


<button id="XXXX:tbl_groupType_IB:0:IB__Viewer:j_idt46395" 
name="XXXX:tbl_groupType_IB:0:IB__Viewer:j_idt46395" class="" onclick="PrimeFaces.ab(s:"XXXX:tbl_groupType_IB:0:IB__Viewer:j_idt46395",onco:function(xhr,status,args)DocViewer_quickViewNoCached('IB__Viewer','en', 'id00000001336875', 'XXXX:mainPanel', 'false', xhr, status,args);,pa:[name:"id",value:"IB__Viewer",name:"documentId",value:"id00000001336875"]);return false;" style="display:none" type="submit" role="button" aria-disabled="false">
    <span class="ui-button-text ui-c">ui-button</span>
</button>


<button id="XXXX:tbl_groupType_IB:0:viewerDocument" name="XXXX:tbl_groupType_IB:0:viewerDocument" 
class="b-button-medium primary" onclick="IB_id00000001336875_Viewer();" type="button" role="button" 
aria-disabled="false">
    <span class="ui-button-text ui-c">View</span>
</button>

这里的问题是DocumentsViewerLoader的ID属性没有解析

id="#'IB_'.concat(dataItemForIB.document.documentId).concat('_Viewer')" 

虽然它下面的一行确实在属性中解决了它

documentId="#dataItemForIB.document.documentId" 

因此,脚本如您在上面看到的那样呈现,而不是

IB_SomeDocumentID_Viewer = function()
        DocViewer_quickViewCached(
                'IB_SomeDocumentID_Viewer',
                'en', 
                'XXXX', 
                'id00000001336875',
                'false');

我已经尝试了很多事情:

id="IB_#dataItemForIB.document.documentId_Viewer" 
id="#'IB_'.concat(dataItemForIB.document.documentId).concat('_Viewer')" 

<c:set var="docId" value="IB_#dataItemForIB.document.documentId_Viewer" />
id="#docId" 

甚至使用数据表的 rowIndexVar 属性,它们都不起作用。

在问这个问题之前也阅读了很多问题,但没有一个与这个问题有关。 我最初的猜测是它与 JSF 生命周期有关,但我不明白为什么相同的确切表达式在属性“documentId”上得到很好的解析,而不是在“id”中。

有人可以帮忙吗?

【问题讨论】:

你找到这个了吗? How to use EL with <ui:repeat var> in id attribute of a JSF component 数据表通常类似于 ui:repeat。您最初的猜测“它与 JSF 生命周期有关”是正确的。这是关于视图构建时间与视图渲染时间的对比。 这能回答你的问题吗? Integrate javascript in JSF composite component, the clean way ***.com/questions/9770358/… 【参考方案1】:

最后,问题似乎出在属性“id”本身的名称上。

经过几次测试,我得到了这个堆栈跟踪:

java.lang.IllegalArgumentException: Empty id attribute is not allowed
    at javax.faces.component.UIComponentBase.validateId(UIComponentBase.java:581)
    at javax.faces.component.UIComponentBase.setId(UIComponentBase.java:413)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.assignUniqueId(ComponentTagHandlerDelegateImpl.java:442)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:179)

正如您在组件的 xhtml 中看到的,ID 属性不是强制性的,它似乎试图验证它,就好像它是 UIComponent 的 ID,所以我决定将属性重命名为“loaderId”并且它得到了解决。

我仍然不清楚为什么会发生这种情况,因此任何进一步的解释都受到好评。

感谢您抽出宝贵时间@Selaron

P.S:这是我第一次回答自己的问题,如果版主认为这应该放在评论中,请随时编辑或让我知道。

【讨论】:

阅读***.com/questions/9770358/…,它解释了吗?

以上是关于EL作为属性传递给数据表内的复合组件时未解析的主要内容,如果未能解决你的问题,请参考以下文章

JSF 复合组件支持 bean EL 表达式作为必需属性的默认值失败,方法未知

JSF ui:composition 和复合组件的问题

将嵌套对象名称作为道具传递给组件

将状态传递给子组件时未定义状态

Vue组件用作插槽的子项时未定义的属性

Vue.js 模态窗口在从另一个组件单击时未打开