简体   繁体   English

在JSF中按ID查找组件

[英]Find component by ID in JSF

I want to find some UIComponent from managed bean by the id that I have provided. 我想通过提供的ID从托管bean中找到一些UIComponent

I have written the following code: 我写了以下代码:

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

I have defined a p:inputTextarea as: 我已经将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" />

Now if a call to the method as getUIComponent("activityDescription") it is returning null , but if I call it as getUIComponent("adminTabView:activityForm:activityDescription") then I can get the org.primefaces.component.inputtextarea.InputTextarea instance. 现在,如果以getUIComponent("activityDescription")的形式调用该方法,则返回null ,但是如果以getUIComponent("adminTabView:activityForm:activityDescription")的形式调用该方法,则可以得到org.primefaces.component.inputtextarea.InputTextarea实例。 。

Is there any way to get the component with only the id ie, "activityDescription" not the absolute id ie, "adminTabView:activityForm:activityDescription"? 有什么方法可以获取仅具有ID(即“ activityDescription”)而不是绝对ID(即“ adminTabView:activityForm:activityDescription”)的组件?

You can use the following code: 您可以使用以下代码:

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

}

This code will find only the first component in the tree with the id you pass. 此代码将仅在树中找到具有您传递的id的第一个组件。 You will have to do something custom if there are 2 components with the same name in the tree (this is possible if they are under 2 different naming containers). 如果树中有2个具有相同名称的组件,则必须做一些自定义操作(如果它们在2个不同的命名容器下,则可能这样做)。

I try this code, and it's help: 我尝试这段代码,它有帮助:

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

Thanks 谢谢

Maybe it's not possible. 也许不可能。 The FacesContext.getCurrentInstance().getViewRoot().findComponent(id) method returns only one UIComponent . FacesContext.getCurrentInstance().getViewRoot().findComponent(id)方法仅返回一个UIComponent The ViewRoot is constructed as a tree so if you have two forms in the view, each one with a component with id="text" , they will have it's parent components added to the id so they won't conflict. ViewRoot构造为一棵树,因此,如果您在视图中有两种形式,每一种形式都有一个id="text"的组件,则它们会将其父组件添加到id中,这样就不会发生冲突。 If you put the two id="text" components within the same form, you will have java.lang.IllegalStateException thrown. 如果将两个id="text"组件放在相同的表单中,则会引发java.lang.IllegalStateException

If you want to find all components with the searched id, you could write a method that implements: 如果要查找具有搜索ID的所有组件,则可以编写一个实现以下方法的方法:

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

Or if you want to find the first occurrence: 或者,如果您想查找第一个匹配项:

UIComponent foundComponent;
for(UIComponent component: FacesContext.getCurrentInstance().getViewRoot().getChildren()) {
    if(component.getId().contains("activityDescription")){
        foundComponent = component;
        break;
    }
}

只需将prependId="false"放到该文本区域所在的表单中即可。

Yes, in all parent components which are NamingContainers you have to add attribute prependId="false" - it will works in <h:form> for sure and should work in others. 是的,在所有作为NamingContainers父组件中,您必须添加属性prependId="false" -它肯定可以在<h:form>中工作,并且应该在其他组件中工作。
If it is not possible to set it via attribute in .xhtml file you have to set such value programaticaly. 如果无法通过.xhtml文件中的属性进行设置,则必须以编程方式设置该值。

Suggestion after question's author comment: 问题作者评论后的建议:

If there is not such attribute in components that you are using try write find method like this: 如果要使用的组件中没有这样的属性,请尝试编写以下查找方法:

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

Next just invoke 接下来只是调用

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

That will help? 那会有所帮助吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM