我想在ajax请求上执行processDecodes
JSF UI组件子树。
如果我指明的话,我会详细说明一点:
<f:ajax event="change" execute="componentId" render="componentPanelId" />
我希望在每个组件上调用processDecodes
,从UIViewRoot开始,到id为componentId的组件,以及所有componentId祖先。
我会这样做因为,ui目标组件的自定义组件父进行一些评估,
特别是它们缩小了XML文档的部分,ui组件值适用于该部分。
假设有以下facelet片段:
<m:node id="root" ref="/Root">
<m:node id="element" ref="Element">
<m:label>Some Label</m:label>
<m:selectOne id="componentId" ref="@Attribute1" execute="@this" render="toRender">
...
</m:selectOne>
<m:selectOne id="toRender" ref="@Attribute2">
...
</m:selectOne>
</m:node>
</m:node>
前提是我已在自定义组件中实现了ajax行为,其属性为execute
和render
。
当componentId ajax事件触发时,我将按指定的顺序处理id为'root','element'和'componentId'的组件。
我尝试使用@form
作为执行属性值:
<m:selectOne id="componentId" ref="@Attribute1" execute="@form" render="toRender">
...
</m:selectOne>
它有效,因为JSF处理表单中的所有ui组件,但这不是理想的行为。
可能通过延长PartialViewContextFactory
?
任何提示或帮助将不胜感激 谢谢
答案 0 :(得分:0)
我找到了一个解决方案,可能不是性能最好的。
我延长了PartialViewContextFactory
,包裹了原始的PartialViewContextFactory
。
新类(如下所示)执行以下操作:
1)它会创建一个新的CustomPartialViewContextImpl
,将原始PartialViewContext
传递给它。
2)它覆盖CustomPartialViewContextImpl.getExecuteIds()
,以便找到所有的祖先。
关于id列表的注释,应该从root用户那里订购。
感谢BalusC的find component algorithm。
public class CustomPartialViewContextFactory extends PartialViewContextFactory {
public static class CustomPartialViewContextImpl extends PartialViewContext {
private FacesContext facesContext;
private PartialViewContext wrappedViewContext;
/**
* Id to execute during ajax request.
*/
private Collection<String> executeIds;
public CustomPartialViewContextImpl(PartialViewContext wrappedViewContext, FacesContext facesContext) {
this.facesContext = facesContext;
this.wrappedViewContext = wrappedViewContext;
}
public Collection<String> getExecuteIds() {
if(this.executeIds == null){
this.executeIds = findAncestors(executeIds);
}
return this.executeIds;
}
// ... delegate other methods to wrappedViewContext
private Collection<String> findAncestors(Collection<String> executeIds) {
Set<String> ids = new HashSet<>(executeIds);
for (String id : executeIds) {
findAncestors(ids, findComponent(id, facesContext));
}
List<String> idList = new ArrayList<>(ids);
Collections.reverse(idList);
return idList;
}
private UIComponent findComponent(final String id, FacesContext context){
UIViewRoot root = context.getViewRoot();
final UIComponent[] found = new UIComponent[1];
root.visitTree(new FullVisitContext(context), new VisitCallback() {
@Override
public VisitResult visit(VisitContext context, UIComponent component) {
if(component.getId().equals(id)){
found[0] = component;
return VisitResult.COMPLETE;
}
return VisitResult.ACCEPT;
}
});
return found[0];
}
private void findAncestors(Set<String> ids, UIComponent component) {
if(component == null){
return;
}
UIComponent parent = component.getParent();
if (parent == null) {
return;
}
String clientId = parent.getClientId(facesContext);
if (StringUtils.isBlank(clientId) || ids.contains(clientId)) {
return;
}
ids.add(clientId);
findAncestors(ids, parent);
}
}
private PartialViewContextFactory parentFactory;
public CustomPartialViewContextFactory(PartialViewContextFactory parentFactory) {
this.parentFactory = parentFactory;
}
@Override
public PartialViewContext getPartialViewContext(FacesContext context) {
return new CustomPartialViewContextImpl(parentFactory.getPartialViewContext(context), context);
}
@Override
public PartialViewContextFactory getWrapped() {
return this.parentFactory;
}
}