52

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

我写了以下代码:

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

我将 a 定义p:inputTextarea为:

<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”?

4

5 回答 5

50

您可以使用以下代码:

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

    return found[0];

}

此代码将仅找到id您传递的树中的第一个组件。如果树中有 2 个具有相同名称的组件(如果它们位于 2 个不同的命名容器下,这是可能的),您将不得不做一些自定义的事情。

于 2013-01-17T12:40:39.213 回答
2

我试试这段代码,它有帮助:

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;
}

谢谢

于 2015-06-03T03:53:53.287 回答
1

也许这是不可能的。该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);
    }
}

或者,如果您想查找第一个匹配项:

UIComponent foundComponent;
for(UIComponent component: FacesContext.getCurrentInstance().getViewRoot().getChildren()) {
    if(component.getId().contains("activityDescription")){
        foundComponent = component;
        break;
    }
}
于 2013-01-17T12:14:35.163 回答
1

只需放入prependId="false"此文本区域所在的表单即可。

于 2013-01-17T13:05:10.190 回答
0

是的,在NamingContainers您必须添加属性的所有父组件中prependId="false"- 它<h:form>肯定会起作用并且应该在其他组件中起作用。
如果无法通过 .xhtml 文件中的属性设置它,则必须以编程方式设置此类值。

问题作者评论后的建议:

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

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;
}   

接下来只是调用

UIComponent iamLookingFor = findComponent(myId, FacesContext.getCurrentInstance().getViewRoot());

那会有帮助吗?

于 2013-01-17T11:54:00.047 回答