每当我的组件被渲染时,我需要一个方法来执行,即第一次和每次更新时都会创建它。
一种方法是使用f:metadata和f:event作为事件“preRenderComponent”。除非我在拥有组件的视图中有f:viewParam的f:元数据,否则它的效果非常好。如果父视图中有f:viewParam,则组件中的f:event将被忽略。
如何解决这个问题,为什么会这样?
以下是重现问题的一些代码:
视图(index.xhtml):
<h:body>
<f:metadata>
<f:viewParam name="vparam" value="#{index.vparam}" />
</f:metadata>
<comp:component />
</h:body>
managedBean(Index.java)
@ManagedBean(name="index")
public class Index implements Serializable {
private String vparam;
public void setVparam(String vparam) {
this.vparam = vparam;
}
public String getVparam() {
return vparam;
}
}
组件视图(component.xhtml):
<h:body>
<composite:interface componentType="component" />
<composite:implementation>
<f:metadata>
<f:event type="preRenderComponent" listener="#{cc.generateString}" />
</f:metadata>
<h:outputText value="#{cc.string}" />
</composite:implementation>
</h:body>
组件的java类(Component.java):
@FacesComponent(value="component")
public class Component extends UINamingContainer implements Serializable {
private String string;
public void generateString(){
System.out.println("*** PRE RENDERING COMPONENT...");
System.out.flush();
string = "It worked!";
}
public String getString(){
return string;
}
}
此代码的预期输出为:字符串“It working!”打印在索引页面中。 实际输出是:nothing,因为空字符串由h:outputText打印为“”。
在日志文件中,“ * ** PRE RENDERING COMPONENT ...”未打印,从未执行过。
如果我从index.xhtml中删除以下行,一切正常:
<f:viewParam name="vparam" value="#{index.vparam}" />
为什么组件的父页面中存在“viewParam”会使JSF忽略组件中的“f:event”?
提前感谢您的回答。
答案 0 :(得分:2)
根据the <f:metadata>
documentation,视图可以只有一个 <f:metadata>
,需要进入模板客户端(顶级XHTML页面,在HTTP请求时打开。
复合材料中的<f:metadata>
被取代。它不属于那里。摆脱它。 <f:event>
本身不需要放在<f:metadata>
内。这是有意的:
<composite:implementation>
<f:event type="preRenderComponent" listener="#{cc.generateString}" />
...
</composite:implementation>
导致您的具体问题,因为第二个<f:metadata>
被完全忽略,包括其所有子女。
是的,你看到了很多<f:metadata><f:viewParam><f:event type="preRenderView">
个例子,但<f:event>
在这个特定情况下实际上是一种解决方法,仅用于放置在同一个{{1}内的自我纪录目的}作为它需要使用的<f:metadata>
。在JSF 2.2中,以<f:viewParam>
的风格引入了正确的方法。另请参阅What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?