Dynamic component IDs for JSF

What’s that you say? Dynamic component IDs for JSF? Impossible! The JSF specification clearly states that the “id” attribute must be a hard coded value. Well I say screw that. There are some times where I want to use a variable to define the ID. Like today at work I came across this exact situation. See I made a template for a specific page and used some t:aliasBean tags to set variables for template. But of course this failed when I wanted to use a variable for the id of an h:form component.

The solution… Far simpler than I thought. All it took was a simple custom component that takes the variable and has its’ renderer set the id. Interested? Read on…

There are several ways to do this, but really you just need to make a wrapper component that takes some attribute as a value binding. Then in the component’s renderer grab the first child element and set its ID to whatever value is pointed to by your value binding. So rather than write a component from scratch, all we really need is a something with a value binding so why not just use an existing ValueHolder component like UIOutput. At work I actually made a new component that extends UIOuput and left the class body blank in case I later want to change things. But for this example let’s just use UIOutput as is. We’ll still need a tag class and a renderer class.

// tag
package com.jsfutils;
public class DynamicIdTag extends UIComponentTagBase {
  public String getComponentType() {
    return "com.jsfutils.DynamicId";
  }
  public String getRendererType() {
    return "com.jsfutils.DynamicId";
  }
}

// renderer
packacge com.jsfutils;
public class DynamicIdTagRenderer extends Renderer {
  public boolean getRendersChildren() { return false; }
  
  public void encodeBegin(FacesContext context, UIComponent component) 
                                         throws IOException {
    
    if (component instanceof ValueHolder) {
      // get the dynamic value and validate it    
      String dynamicId = (String) ((ValueHolder)component).getValue();
       
      if (dynamicId == null || dynamicId.equals("")) return;

      // find the first child component
      List children = component.getChildren();
      if (children.isEmpty) return ;
    
      // set the id
      UIComponent firstChild = (UIComponent) children.get(0);
      firstChild.setId(dynamicId);
    }
  }
}

// faces-config
<component>
  <component-type>com.jsfutils.DynamicId</component-type>
  <component-class>javax.faces.component.UIOutput</component-class>
</component>

<render-kit>
  <renderer>
    <renderer-type>com.jsfutils.DynamicId</renderer-type>
    <renderer-class>om.jsfutils.DynamicIdRenderer</renderer-class>
  </renderer>
</render-kit>

// tld
<taglib>
  <tag>
    <name>dynamicId</name>
    <tagclass>com.jsfutils.DynamicIdTag</tagclass>
    <attribute>
      <name>value</name>
      <required>true</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
  </tag>
</taglib>

// use in a JSP/JSF page assuming the tag prefix is "jsfutil"
<jsfutil:dynamicId value="#{backingBean.myFormIdValue}">
  <h:form>
    <%-- contents of the form --%>
  </h:form>
</jsfutil:dynamicId>

And there you have it. Dynamic component IDs! When the page loads the form will be rendered with the id specified by the backing bean and of course the actual component ID in the JSF component tree will also have this id.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: