在 JSF 中按 ID 查找组件
Posted
技术标签:
【中文标题】在 JSF 中按 ID 查找组件【英文标题】:Find component by ID in JSF 【发布时间】:2012-12-31 22:53:57 【问题描述】:我想通过我提供的 id 从托管 bean 中找到一些 UIComponent
。
我写了以下代码:
private UIComponent getUIComponent(String id)
return FacesContext.getCurrentInstance().getViewRoot().findComponent(id) ;
我已将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”?
【问题讨论】:
我可以知道为什么-1吗?这不是一个有效的问题吗? 也许只是一些在[java]
标签中徘徊的天真用户不知道你在说什么。
我注意到您使用的是 primefaces。你检查过 ComponentUtils.java 吗? grepcode.com/file/repository.primefaces.org/org.primefaces/…
@Tapas Bose:一个绝妙的问题实际上清除了我对 UIComponent 类的可视化。从我这边+1。这类问题应该得到更多的东西。
【参考方案1】:
您可以使用以下代码:
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 个不同的命名容器下,这是可能的),您将不得不做一些自定义。
【讨论】:
if (component != null && component.getId() != null && component.getId().equals(id)) // 获取那些 null 检查 针对 JSF API 进行编译时,不能使用FullVisitContext
。但是,可以使用VisitContext.createVisitContext(FacesContext.getCurrentInstance())
创建访问上下文。
即使有空检查,这对我来说也陷入了无限循环 - 所以这不是一个很好的解决方案。
您检查component
不是null
。虽然一般来说是一个很好的做法,但visitTree
是否有可能返回组件null
?【参考方案2】:
只需将prependId="false"
输入到此文本区域所在的表单中即可。
【讨论】:
糟糕的建议。不要那样做。永远不要使用prependId="false"
。相关:***.com/questions/7415230/… 它只是(暂时)引入以使基于非 ajax 的j_security_check
表单无论如何都可以与 JSF 1.x 一起使用。永远不要在 JSF 2.x 上使用它。【参考方案3】:
我试试这段代码,它很有帮助:
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;
谢谢
【讨论】:
【参考方案4】:是的,在 NamingContainers
的所有父组件中,您必须添加属性 prependId="false"
- 它肯定会在 <h:form>
中工作,并且应该在其他组件中工作。 如果无法通过 .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;
接下来调用
UIComponent iamLookingFor = findComponent(myId, FacesContext.getCurrentInstance().getViewRoot());
这会有帮助吗?
【讨论】:
感谢您的回复。在<h:form/>
中有一个属性prependId="false"
,但<p:tabView/>
没有它。【参考方案5】:
也许这是不可能的。 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;
【讨论】:
有一个问题,因为如果您从视图根目录获取子项,则可能会有另一个带有孩子的组件,然后在其中的下一个组件等等......您必须在这里使用递归 - 我认为没有其他选择跨度> 当然,你是对的,它是一棵树。我忽略了数据结构。 请注意,UIComponent.findComponent 上的文档暗示了一种使用带有回调的 invokeOnComponent 通过其 clientId 搜索组件的方法。 @elias 我认为您的回答完全符合 OP 的需求。以上是关于在 JSF 中按 ID 查找组件的主要内容,如果未能解决你的问题,请参考以下文章