JSF 2——在 f:ajax 上具有可选监听器属性的复合组件
Posted
技术标签:
【中文标题】JSF 2——在 f:ajax 上具有可选监听器属性的复合组件【英文标题】:JSF 2 -- Composite component with optional listener attribute on f:ajax 【发布时间】:2012-07-07 06:31:37 【问题描述】:我有一个看起来像这样的复合组件:
<!DOCTYPE html>
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:dm="http://davemaple.com/dm-taglib"
xmlns:rich="http://richfaces.org/rich"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j">
<cc:interface>
<cc:attribute name="styleClass" />
<cc:attribute name="textBoxStyleClass" />
<cc:attribute name="inputTextId" />
<cc:attribute name="labelText" />
<cc:attribute name="tabindex" />
<cc:attribute name="required" default="false" />
<cc:attribute name="requiredMessage" />
<cc:attribute name="validatorId" />
<cc:attribute name="converterId" />
<cc:attribute name="title"/>
<cc:attribute name="style"/>
<cc:attribute name="unicodeSupport" default="false"/>
<cc:attribute name="tooltip" default="false"/>
<cc:attribute name="tooltipText" default=""/>
<cc:attribute name="tooltipText" default=""/>
<cc:attribute name="onfail" default=""/>
<cc:attribute name="onpass" default=""/>
</cc:interface>
<cc:implementation>
<ui:param name="converterId" value="#! empty cc.attrs.converterId ? cc.attrs.converterId : 'universalConverter'" />
<ui:param name="validatorId" value="#! empty cc.attrs.validatorId ? cc.attrs.validatorId : 'universalValidator'" />
<ui:param name="component" value="#formFieldBean.getComponent(cc.attrs.inputTextId)" />
<ui:param name="componentValid" value="#((facesContext.maximumSeverity == null and empty component.valid) or component.valid) ? true : false" />
<ui:param name="requiredMessage" value="#! empty cc.attrs.requiredMessage ? cc.attrs.requiredMessage : msg['validation.generic.requiredMessage']" />
<ui:param name="clientIdEscaped" value="#fn:replace(cc.clientId, ':', '\\\\\\\\:')" />
<h:panelGroup layout="block" id="#cc.attrs.inputTextIdValidPanel" style="display:none;">
<input type="hidden" id="#cc.attrs.inputTextIdValid" value="#componentValid" />
</h:panelGroup>
<dm:outputLabel for="#cc.clientId:#cc.attrs.inputTextId" id="#cc.attrs.inputTextIdLabel">#cc.attrs.labelText</dm:outputLabel>
<dm:inputText
styleClass="#cc.attrs.textBoxStyleClass"
tabindex="#cc.attrs.tabindex"
id="#cc.attrs.inputTextId"
required="#cc.attrs.required"
requiredMessage="#requiredMessage"
title="#cc.attrs.title"
unicodeSupport="#cc.attrs.unicodeSupport">
<f:validator validatorId="#validatorId" />
<f:converter converterId="#converterId" />
<cc:insertChildren />
<f:ajax
event="blur"
execute="@this"
render="#cc.attrs.inputTextIdValidPanel #cc.attrs.inputTextIdMsg"
onevent="on#cc.attrs.inputTextIdEvent" />
</dm:inputText>
<rich:message for="#cc.clientId:#cc.attrs.inputTextId" id="#cc.attrs.inputTextIdMsg" style="display: none;" />
<script>
function on#cc.attrs.inputTextIdEvent(e)
if(e.status == 'success')
$('##clientIdEscaped\\:#cc.attrs.inputTextId').trigger($('##cc.attrs.inputTextIdValid').val()=='true'?'pass':'fail');
$('##clientIdEscaped\\:#cc.attrs.inputTextId').bind('fail', function()
$('##clientIdEscaped\\:#cc.attrs.inputTextId, ##clientIdEscaped\\:#cc.attrs.inputTextIdLabel, ##cc.attrs.inputTextIdMsg, ##cc.idMsg').addClass('error');
$('##cc.idMsg').html($('##clientIdEscaped\\:#cc.attrs.inputTextIdMsg').html());
#cc.attrs.onfail
).bind('pass', function()
$('##clientIdEscaped\\:#cc.attrs.inputTextId, ##clientIdEscaped\\:#cc.attrs.inputTextIdLabel, ##cc.attrs.inputTextIdMsg, ##cc.idMsg').removeClass('error');
$('##cc.idMsg').html($('##clientIdEscaped\\:#cc.attrs.inputTextIdMsg').html());
#cc.attrs.onpass
);
</script>
<a4j:region rendered="#facesContext.maximumSeverity != null and !componentValid">
<script>
$(document).ready(function()
$('##clientIdEscaped\\:#cc.attrs.inputTextId').trigger('fail');
);
</script>
</a4j:region>
</cc:implementation>
</html>
我希望能够添加一个可选的“侦听器”属性,如果定义了该属性,它将向我的 f:ajax 添加一个事件侦听器,但我无法弄清楚如何实现这一点。任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:不幸的是,以上所有方法都对我不起作用,所以我摆弄了一下,想出了以下解决方案。
<cc:interface type="someComponent">
<cc:attribute name="listener" method-signature="void listener()" />
</cc:interface>
<cc:implementation>
<h:someComponent>
<p:ajax listener="#cc.attrs.listener" onstart="#cc.attrs.containsKey('listener') ? '' : 'return false'" />
</h:someComponent>
</cc:implementation>
这将始终绑定 ajax 行为,但只有在实际存在侦听器时才执行它。
【讨论】:
【参考方案2】:我也有同样的问题,我的解决方案是为 action 方法创建默认值。我只需要创建一个类:MyComponent.java
,其中包含所有默认方法签名。
<cc:interface>
<cc:attribute name="listener" method-signature="void listener()"
default="#myComponent.doNothing()" />
</cc:interface>
<cc:implementation>
<h:someComponent>
<f:ajax listener="#cc.attrs.listener" />
</h:someComponent>
</cc:implementation>
【讨论】:
【参考方案3】:您需要指定<cc:attribute>
标记的method-signature
属性,以便将属性值视为方法表达式。您可以使用 JSTL 视图构建时间标记 <c:if>
有条件地添加 <f:ajax>
标记。
<cc:interface>
<cc:attribute name="listener" method-signature="void listener()" />
</cc:interface>
<cc:implementation>
<h:someComponent>
<c:if test="#cc.getValueExpression('listener') != null">
<f:ajax listener="#cc.attrs.listener" />
</c:if>
</h:someComponent>
</cc:implementation>
(#not empty cc.attrs.listener
不起作用,因为 EL 会隐式地将属性评估为值表达式)
那么你可以如下使用它:
<my:someComposite listener="#bean.listener" />
或者当您的环境不支持 EL 2.2 时,则创建一个支持组件:
@FacesComponent("someComponent")
public class SomeComponent extends UINamingContainer
public boolean isHasListener()
return getValueExpression("listener") != null;
要声明并用作
<cc:interface type="someComponent">
<cc:attribute name="listener" method-signature="void listener()" />
</cc:interface>
<cc:implementation>
<h:someComponent>
<c:if test="#cc.hasListener">
<f:ajax listener="#cc.attrs.listener" />
</c:if>
</h:someComponent>
</cc:implementation>
【讨论】:
好的。我已经做到了这一点,但我希望它是一个可选属性。当组件的客户端不提供它时,我不希望 f:ajax 使用它。有没有办法让它在 f:ajax 上成为可选的? 嗯,这样不行。<c:if>
尝试将其解析为值表达式:/ 抱歉,我将不得不回复我的答案。
好的。选项 2 没有漂亮的界面,但我想我会选择它,这样我就可以隐藏其他 f:ajax 功能。
理论上,当使用“支持组件”(<cc:interface componentType>
)时应该是可行的,它有一个 getter 方法来检查是否定义了“listener”属性,以便您可以使用<c:if test="#cc.hasListener">
或者。没有办法告诉 EL 不将其解析为值表达式。由于#cc.attrs
的EL 解析器,即使#not cc.attrs.containsKey('listener')
也无法工作。我已经更新了答案。
更好的是,#not empty cc.getValueExpression('listener')
为我工作。很抱歉这么多更新,这对我来说也是第一次:)以上是关于JSF 2——在 f:ajax 上具有可选监听器属性的复合组件的主要内容,如果未能解决你的问题,请参考以下文章
JSF f:ajax 监听器 vs commandButton 动作
JSF 2 - 如何将 Ajax 侦听器方法添加到复合组件接口?
使用 f:ajax 时 JSF 不触发 bean setter