Jsf 计算UIComponent客户端ID的有效方法?

Jsf 计算UIComponent客户端ID的有效方法?,jsf,Jsf,实际上,在我的JSF应用程序中,我有以下代码来根据组件id计算组件clientId: public static String getComponentClientId(String id) { try { FacesContext fctx = FacesContext.getCurrentInstance(); UIComponent found = getComponentWithId(fctx.getViewRoot(), id); if (found!=nu

实际上,在我的JSF应用程序中,我有以下代码来根据组件id计算组件clientId

public static String getComponentClientId(String id) {
  try {
    FacesContext fctx = FacesContext.getCurrentInstance();
    UIComponent found = getComponentWithId(fctx.getViewRoot(), id);
    if (found!=null)
      return found.getClientId(fctx);           
    else
      return null;
  } catch (Exception e) {
    return null;
  }     
}
public static UIComponent getComponentWithId(UIComponent parent, String id) {
  for (Iterator<UIComponent> chs = parent.getFacetsAndChildren(); chs.hasNext();) {
    UIComponent ch = chs.next();
    if (ch.getId().equalsIgnoreCase(id))
     return ch;     
    else {
     UIComponent found = getComponentWithId(ch, id);
     if (found!=null)
       return found;
    }
  }
  return null;
}
公共静态字符串getComponentClientId(字符串id){
试一试{
FacesContext fctx=FacesContext.getCurrentInstance();
UIComponent found=getComponentWithId(fctx.getViewRoot(),id);
如果(找到!=null)
找到返回。getClientId(fctx);
其他的
返回null;
}捕获(例外e){
返回null;
}     
}
公共静态UIComponent getComponentWithId(UIComponent父级,字符串id){
for(迭代器chs=parent.getFacetsAndChildren();chs.hasNext();){
UIComponent ch=chs.next();
if(ch.getId().equalsIgnoreCase(id))
返回ch;
否则{
UIComponent found=getComponentWithId(ch,id);
如果(找到!=null)
发现退货;
}
}
返回null;
}
该方法可以工作,但它可以在视图组件树中导航,因此效率可能非常低,特别是在存在高度填充的页面时。有一种我不知道的聪明方法或API可以使工作更快/更容易?

我不知道

很难缓存此信息,因为:

  • 的实例与其ClientID之间的关系可以是1:N。这对于管理其子对象状态的组件是必需的。中的返回值可以是上下文相关的
  • UIComponent实例的生存期可能不会超过请求。的某些实现可以配置为在会话中保存视图状态,在这种情况下,对象的生存期可能会更长,但让代码依赖于此会使其脆弱,并且很容易导致内存泄漏
  • 视图可以是动态的。诚然,这是一种边缘情况,但可以通过编程方式创建组件
  • 在尝试其他方法之前,我会证明这是一个问题


    你没有说你需要clientid做什么,但我猜它是为了某种形式的JavaScript支持。考虑并通过其渲染器发布标记。这可以与属性一起使用,类似于。在同一个房间里找到邻居相对容易。您可以在渲染器实现中使用如下代码:

    // untested code!
    String clientId = mycomponent.getClientId(context);
    // get id of target control
    String _for = mycomponent.getFor();
    int n = clientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
    String targetClientId = clientId.substring(0, n)
            + NamingContainer.SEPARATOR_CHAR + _for;
    ResponseWriter writer = context.getResponseWriter();
    // write markup
    
    组件通常需要共享一个命名容器来使用彼此的clientId,所以这不是一个很大的限制。如果可以将组件设置为子组件,则更容易找到父组件

    当然,这种方法也有问题。它使您的UI树更大,对生命周期处理和状态管理产生连锁反应。权衡是否值得,需要测试


    编辑:

    我在周末考虑过这件事。因为50%的JSF查询似乎都是关于如何使用IDs的,所以我写了一篇文章,这样我就可以让人们参考它了。在中包含了一种缓存ID的机制(有点!)和一些示例代码。

    据我所知不是这样

    很难缓存此信息,因为:

  • 的实例与其ClientID之间的关系可以是1:N。这对于管理其子对象状态的组件是必需的。中的返回值可以是上下文相关的
  • UIComponent实例的生存期可能不会超过请求。的某些实现可以配置为在会话中保存视图状态,在这种情况下,对象的生存期可能会更长,但让代码依赖于此会使其脆弱,并且很容易导致内存泄漏
  • 视图可以是动态的。诚然,这是一种边缘情况,但可以通过编程方式创建组件
  • 在尝试其他方法之前,我会证明这是一个问题


    你没有说你需要clientid做什么,但我猜它是为了某种形式的JavaScript支持。考虑并通过其渲染器发布标记。这可以与属性一起使用,类似于。在同一个房间里找到邻居相对容易。您可以在渲染器实现中使用如下代码:

    // untested code!
    String clientId = mycomponent.getClientId(context);
    // get id of target control
    String _for = mycomponent.getFor();
    int n = clientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
    String targetClientId = clientId.substring(0, n)
            + NamingContainer.SEPARATOR_CHAR + _for;
    ResponseWriter writer = context.getResponseWriter();
    // write markup
    
    组件通常需要共享一个命名容器来使用彼此的clientId,所以这不是一个很大的限制。如果可以将组件设置为子组件,则更容易找到父组件

    当然,这种方法也有问题。它使您的UI树更大,对生命周期处理和状态管理产生连锁反应。权衡是否值得,需要测试


    编辑:


    我在周末考虑过这件事。因为50%的JSF查询似乎都是关于如何使用IDs的,所以我写了一篇文章,这样我就可以让人们参考它了。中包含一种缓存ID的机制(有点!)和一些示例代码。

    谢谢你,McDowell。我只需要ClientID来发送正确组件的消息。我不想将每个组件都绑定到我的支持bean:这是一种正确的方法吗?看看taglib函数(参见博客链接)。如果你能改进我的解决方案,我很想听听。谢谢你,麦克道尔。我只需要ClientID来发送正确组件的消息。我不想将每个组件都绑定到我的支持bean:这是一种正确的方法吗?看看taglib函数(参见博客链接)。如果你能改进我的解决方案,我很想听听。仅供参考:只有在视图的ID是唯一的情况下,此算法才有效。最近回到规范,我注意到组件标识符只需要对最近的NamingContainer唯一。仅供参考:只有当ID对视图唯一时,该算法才有效。回到最近的规范,我注意到组件标识符只需要对最近的NamingContainer是唯一的。