views:

414

answers:

1

I know of two ways of creating custom JSF components: 1. Native JSF way: creating JSF component class, tag, etc. 2. Facelets way: defining component in a xhtml file and then creating appropriate decrption in facelets taglib.

Currently I work on a project in which introducing facelets is unfortunately out of the question. On the other hand, creating custom components the standard JSF way seems like a pain in the ass.

Is there maybe a third party library that allows creating custom components in the way similar to facelets but doesn't entail the need of using non-standard renderer?

+1  A: 

You can do a limited amount of templating using (for example) jsp:include and f:subview.

Alternatively, you can extend a UIComponent overriding selected methods and then provide it via an existing tag and a managed bean using the binding attribute. This still requires a reasonably detailed understanding of component development (and the consequences of this choice), but could cut down the number of files/volume of code significantly.

This approach is a bit of a hack, but might be OK for short-term stuff. You wouldn't do it for component libraries you want to distribute or components requiring long term maintenance.

The new component:

public class QuickComponent extends HtmlOutputText {
  @Override public void encodeAll(FacesContext context) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    writer.writeText("I'm not really a HtmlOutputText", null);
    for (UIComponent kid : getChildren()) {
      if (kid instanceof UIParameter) {
        UIParameter param = (UIParameter) kid;
        writer.startElement("br", this);
        writer.endElement("br");
        writer.writeText(param.getName() + "=" + param.getValue(), null);
      }
    }
  }
}

The bean providing an instance:

/**Request-scope managed bean defined in faces-config.xml*/
public class QuickComponentProviderBean {
  private QuickComponent quick;

  public void setQuick(QuickComponent quick) {
    this.quick = quick;
  }

  public QuickComponent getQuick() {
    if (quick == null) {
      quick = new QuickComponent();
    }
    return quick;
  }
}

Note: don't reuse a single bean property for multiple tags in your views, or they'll reference the same object instance.

Adding the new component to the view:

<h:outputText binding="#{quickComponentProviderBean.quick}">
  <f:param name="Hello" value="World" />
</h:outputText>

Note: the attributes that can be defined have not changed. They're fixed by the TLD.

McDowell