当作为属性传递给数据表内的复合组件时,EL 未解析
EL not resolved when passed as attribute to composite component inside datatable
我遇到了 EL 表达式在复合组件初始化时未解析的问题。这是代码:
<p:column sortable="false" toggleable="false" width="20%">
<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 属性和 none 也有效。
在问这个问题之前也阅读了很多问题,但其中 none 个问题与这个问题有关。
我最初的猜测是它与 JSF 生命周期有关,但我不明白为什么相同的表达式在属性“documentId”而不是“id”中得到很好的解析。
任何人都可以帮忙吗?
最后看来问题出在属性名称 "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:这是我第一次回答我自己的问题,如果版主认为这应该放在评论中,请随时编辑它或让我知道。
我遇到了 EL 表达式在复合组件初始化时未解析的问题。这是代码:
<p:column sortable="false" toggleable="false" width="20%">
<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 属性和 none 也有效。
在问这个问题之前也阅读了很多问题,但其中 none 个问题与这个问题有关。 我最初的猜测是它与 JSF 生命周期有关,但我不明白为什么相同的表达式在属性“documentId”而不是“id”中得到很好的解析。
任何人都可以帮忙吗?
最后看来问题出在属性名称 "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:这是我第一次回答我自己的问题,如果版主认为这应该放在评论中,请随时编辑它或让我知道。