Thursday, October 13, 2011

Replacement for s:decorate in Seam 3

I've been doing a gap analysis for our migration from Seam 2 to Seam 3, and I was dismayed to find that the <s:decorate> tag is gone! In Seam 2, you create a template like this:

<ui:composition  xmlns="http://www.w3.org/1999/xhtml"
                 xmlns:ui="http://java.sun.com/jsf/facelets"
                 xmlns:h="http://java.sun.com/jsf/html"
                 xmlns:f="http://java.sun.com/jsf/core"
                 xmlns:s="http://jboss.com/products/seam/taglib">

    <div class="prop">
        <s:label styleClass="nameEdit #{invalid?'errors':''}">
            <s:span styleClass="required"
               rendered="#{required}">*</s:span>
            <ui:insert name="label"/>
        </s:label>

        <span class="value #{invalid?'errors':''}">
            <s:validateAll>
                <ui:insert/>
            </s:validateAll>
        </span>

        <span class="error">
            <h:graphicImage value="/img/error.gif" 
                rendered="#{invalid}" styleClass="errors"/>
        </span>
    </div>
</ui:composition>

And then reference it using <s:decorate>

<s:decorate template="edit.xhtml">
  <ui:define name="label">Country:</ui:define>
  <h:inputText value="#{location.country}" required="true"/>
</s:decorate>

And now required fields are noted with an asterisk (*), all fields are automatically validated, and when they have errors, a special style is applied and the error message appears to the right of the field:


Note: this is all documented in Section 33.1.13 of the Seam 2 reference.

Pretty slick! I definitely need this functionality when I migrate to Seam 3, but the <s:decorate> tag is gone, and I had a hard time finding a replacement.

Replacing with UIInputContainer

Fortunately, a close replacement actually exists in Seam 3's Faces module... it just isn't described as such! Seam Faces provides a component called UIInputContainer. When this is combined with a JSF 2 composite component, you can get the same functionality.

First, create your composite component. I created mine at WebContent/resources/orr/decorate.xhtml:

<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:composite="http://java.sun.com/jsf/composite">

<composite:interface componentType="org.jboss.seam.faces.InputContainer" />

<composite:implementation>
 <div>
  <h:outputLabel id="label" value="#{cc.attrs.label}:"
   styleClass="#{cc.attrs.invalid ? 'invalid' : ''}">

   <h:outputText styleClass="required" rendered="#{cc.attrs.required}"
    value="*" />

  </h:outputLabel>

  <!-- h:panelGroup is a workaround for a JSF bug, see http://java.net/jira/browse/JAVASERVERFACES-1991  -->
  <h:panelGroup styleClass="value #{invalid?'errors':''}" >
   <composite:insertChildren />
  </h:panelGroup>

  <h:message id="message" errorClass="invalid message"
   rendered="#{cc.attrs.invalid}" />
 </div>
</composite:implementation>
</html>

Since I put the composite component in WebContent/resources/orr/decorate.xhtml, the namespace is http://java.sun.com/jsf/composite/orr and the tag name is decorate.

Now use this new tag in your Facelets page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:o="http://java.sun.com/jsf/composite/orr">



<o:decorate label="Country:">
    <h:inputText value="#{location.country}" required="true"/>
</o:decorate>

And that's it! This will generate roughly the same output and behavior as Seam 2's <s:decorate> tag. So all along, there was a pretty good replacement, but either this wasn't made clear anywhere, or my Google skills aren't quite as good as I think. I imagine this would be documented in JBoss's Seam 2 to Seam 3 migration guide, if such a thing existed...

5 comments:

  1. I see you like the tool FormBuilder :).. soon a new version JFormBuilder comes up! perhaps with will solve all the things like this!

    ReplyDelete
  2. Hi Jerry - I'd be interested in the results of your gap analysis as we're about to go through a similar exercise. Everything I've found so far appears to be a bit out of date - can't find anything substantial beyond December 2011 - so anything you could point me at would be very useful!

    Cheers
    Ian

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. By the way thanks for the s:decorate replacement solution - just what we need!

    ReplyDelete
  5. Glad you found this helpful!

    In the middle of our evaluation of migrating to Seam 3, news started to come out about the community discontinuing Seam and focusing on Apache DeltaSpike. We decided to stay on Seam 2 and wait to see how things settled out.

    I've since moved on to a non-Seam environment, but here's a recent article discussing the future of Seam and DeltaSpike: http://www.infoq.com/news/2012/04/seam-deltaspike

    FWIW, here are a couple links that helped me when I was evaluating Seam 3:

    http://seamframework.org/Seam3/Seam2ToSeam3MigrationNotes
    http://javalabor.blogspot.com/2011/08/our-seam-2-to-jee-6-replacement-list.html

    ReplyDelete