在JSF中按ID查找组件

在JSF中按ID查找组件,jsf,jsf-2,primefaces,uicomponents,Jsf,Jsf 2,Primefaces,Uicomponents,我想通过我提供的id从托管bean中找到一些UIComponent 我编写了以下代码: private UIComponent getUIComponent(String id) { return FacesContext.getCurrentInstance().getViewRoot().findComponent(id) ; } public UIComponent findComponent(final String id) { FacesContext

我想通过我提供的id从托管bean中找到一些
UIComponent

我编写了以下代码:

private UIComponent getUIComponent(String id) {  
      return FacesContext.getCurrentInstance().getViewRoot().findComponent(id) ;  
}
public UIComponent findComponent(final String id) {

    FacesContext context = FacesContext.getCurrentInstance(); 
    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 != null 
                && component.getId() != null 
                && component.getId().equals(id)) {
                found[0] = component;
                return VisitResult.COMPLETE;
            }
            return VisitResult.ACCEPT;              
        }
    });

    return found[0];

}
我已将
p:inputExtArea
定义为:

<p:inputTextarea id="activityDescription" value="#{adminController.activityDTO.activityDescription}" required="true" maxlength="120"
    autoResize="true" counter="counter" counterTemplate="{0} characters remaining." cols="80" rows="2" />

现在,如果调用方法为
getUIComponent(“activityDescription”)
它返回
null
,但是如果调用方法为
getUIComponent(“adminTabView:activityForm:activityDescription”)
,那么我可以得到
org.primefaces.component.inputtextarea.inputtextarea
实例


有没有办法只获取id为“activityDescription”而不是绝对id为“adminTabView:activityForm:activityDescription”的组件?

是的,在所有为
NamingContainers
的父组件中,必须添加属性
prependId=“false”
-它肯定会在
中工作,并且应该在其他系统中工作
如果无法通过.xhtml文件中的属性进行设置,则必须通过编程方式设置该值

问题作者评论后的建议:

如果您正在使用的组件中没有这样的属性,请尝试使用以下方法:

private UIComponent findComponent(String id, UIComponent where) {
if (where == null) {
   return null;
}
else if (where.getId().equals(id)) {
   return where;
}
else {
   List<UIComponent> childrenList = where.getChildren();
   if (childrenList == null || childrenList.isEmpty()) {
      return null;
   }
   for (UIComponent child : childrenList) {
      UIComponent result = null;
      result = findComponent(id, child);
      if(result != null) {
         return result;
   }
   return null;
}   

那会有帮助吗?

也许这是不可能的。
FacesContext.getCurrentInstance().getViewRoot().findComponent(id)
方法只返回一个
UIComponent
。ViewRoot被构造为一个树,因此,如果视图中有两个表单,每个表单都有一个带有
id=“text”
的组件,则它们将其父组件添加到id中,这样它们就不会发生冲突。如果将两个
id=“text”
组件放在同一个表单中,将抛出
java.lang.IllegalStateException

如果要查找具有搜索id的所有组件,可以编写一个实现以下功能的方法:

List<UIComponent> foundComponents = new ArrayList();
for(UIComponent component: FacesContext.getCurrentInstance().getViewRoot().getChildren()) {
    if(component.getId().contains("activityDescription")){
        foundComponents.add(component);
    }
}

您可以使用以下代码:

private UIComponent getUIComponent(String id) {  
      return FacesContext.getCurrentInstance().getViewRoot().findComponent(id) ;  
}
public UIComponent findComponent(final String id) {

    FacesContext context = FacesContext.getCurrentInstance(); 
    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 != null 
                && component.getId() != null 
                && component.getId().equals(id)) {
                found[0] = component;
                return VisitResult.COMPLETE;
            }
            return VisitResult.ACCEPT;              
        }
    });

    return found[0];

}

此代码将只找到树中第一个具有您传递的
id
的组件。如果树中有两个具有相同名称的组件(如果它们位于两个不同的命名容器下,这是可能的),则必须执行自定义操作。

只需将
prependId=“false”
添加到该文本区域所在的表单中即可。

我尝试了此代码,它提供了帮助:

private static UIComponent getUIComponentOfId(UIComponent root, String id){
    if(root.getId().equals(id)){
        return root;
    }
    if(root.getChildCount() > 0){
        for(UIComponent subUiComponent : root.getChildren()){
                UIComponent returnComponent = getUIComponentOfId(subUiComponent, id);
                if(returnComponent != null){
                    return returnComponent;
            }
        }
    }
    return null;
}

谢谢

我可以知道原因吗-1?这不是一个正确的问题吗?也许只是一些天真的用户徘徊在
[java]
标签中,不知道你在说什么。我注意到你在使用primefaces。您检查过ComponentUtils.java吗@Tapas Bose:一个聪明的问题,实际上清除了我对UIComponent类的想象+从我这边。这些问题应该得到更多的回答。谢谢你的回答。在
中有一个属性
prependId=“false”
,但
中没有该属性。有一个问题,因为如果您从视图根中获取子级,则可能会有另一个包含chilren的组件,然后在该组件中找到下一个以及更多。。。你必须在这里使用递归-我认为没有其他选择当然,你是对的,它是一棵树。我忽略了数据结构。请注意,docs on提示了一种使用带有回调的invokeOnComponent通过其clientId搜索组件的方法。@elias我认为您的答案完全符合OP的需要。如果(component!=null&&component.getId()!=null&&component.getId().equals(id))//在根据JSF API编译时获取这些空检查,无法使用
FullVisitContext
。然而,使用
VisitContext.createVisitContext(FacesContext.getCurrentInstance())
创建访问上下文是可能的。即使使用空检查,这也会让我陷入无限循环中——因此这不是一个很好的解决方案。糟糕的建议。不要那样做。切勿使用
prependId=“false”
。相关:它只是(暂时)被引入,以使非基于ajax的
j_security_check
表单能够与JSF1.x一起使用。永远不要在JSF2.x上使用它。