这个问题是从JSF2: why does empty test in rendered of panelGroup in composite prevent action from being called?
的部分答案中产生的在下面,Element是一个名称和ID的@Entity。一个view.xhtml JSF页面将id作为viewParam,并使用@ManagedBean @RequestScoped ElementController的setID(Long id)触发从数据库中加载相应的Element(在问题中不再起作用),并且发现元素被设置为'当前'元素可用(由于历史原因,名称略有不同)作为元素getSelected()。
view.xhtml页面执行渲染属性测试#{not empty elementController.selected},并且有啊:commandButton with action执行faces-redirect,以及id作为查询参数,返回view.xhtml页。
由于某种原因,我不完全理解,在表单提交时,在应用请求阶段和进程验证阶段都调用了测试(因此getSelected),之后可以设置viewParam id(因此在当前/之前)可以在更新模型值阶段找到并设置所选元素。
极大缩写的view.xhtml页面是:
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{elementController.id}"/>
</f:metadata>
</f:view>
<h:body>
<h:form>
<h:panelGroup rendered="#{not empty elementController.selected}">
<h:outputText value="#{elementController.selected.name}"/>
</h:panelGroup>
<h:commandButton value="Apply" action="#{elementController.action}" />
</h:form>
</h:body>
(表单提交的意义在上面丢失,但对于这个问题并不重要。)
ElementController扩展了RequestController:
public void setId(Long id) {
log_debug("setId","id",id);
if (id != null) {
this.id = id;
T found = (T) getAbstractFacade().find(id);
if (found == null) {
String $error = "No object with id(" + id + ") found for class " + getManagedClass().getSimpleName();
log_error($error);
}
setCurrent(found);
}
}
public T getSelected() {
log_debug("getSelected","current",current);
if (current == null) {
log_warn("getSelected","null current Element");
}
return current;
}
public Object action() {
String $i = "action";
log_debug($i);
if (current==null) {
log_warn($i, "can't generate action outcome for null current element");
return null;
}
return "/view?faces-redirect=true&id="+current.getId();
}
现在在表单提交时,getSelected()恰好被调用两次,当current == null时,一次在apply请求值阶段,一次在进程验证阶段,由于测试#{not empty elementController.selected因为view.xhtml中的viewParam,可以在设置id之前(因此加载Element实体)。
问题是,为什么在应用请求阶段和流程验证阶段都会调用render =#{not empty elementController.selected}?
在执行带有id参数的view.xhtml的初始GET加载时,不会在这些阶段调用它,仅在表单提交POST和后续重定向和GET期间。
答案 0 :(得分:4)
在回发后查询rendered
属性两次或更多次的原因是因为JSF遍历每个阶段的组件树。
名称'rendered'可能不是最好的名字,因为它不仅仅是渲染它应用条件的组件,而是实际上处理它。
首先咨询“应用请求值”,以查看是否应该处理该组件及其子组件以将这些请求值应用于它们。它在“过程验证”中再次被咨询,因为它的价值可能在不同阶段之间发生了变化。
在我执行初始GET加载的那些阶段中没有调用它,因为当你执行GET时,组件树不会在这些阶段中遍历(只处理元数据,这就是视图参数被放置的原因)在一个特殊的元数据部分)。
为了在回发后使操作方法中的GET请求中提供的id
可用,您最好使用视图范围(@ViewScoped
)作为辅助bean。