views:

682

answers:

1

I'm writting a custom JSF component that will render image transitions for a set of specified images. The list of images to be used by the component will be specified by the users of the component.

The main component will do the rendering and the resulting markup is not html.

I'm just learning JSF and I was wondering if there is an established pattern for passing a list of attributes of parameters to a custom component:

Would the user be expecting to pass attributes like this:
<i:imageComponent width="480" height="320" imageUrls="img1Url1, imgUrl2" imageCaptions="imageCaption1, imageCaptions2"/>

and then I could convert those attributes to a list of the server using a converter or would this be more natural?

<i:imageComponent width="480" height="320">
<i:image id="im1" href="url1" caption="caption1"/>
<i:image id="im2" href="url2" caption="caption2"/>
<i:imageComponent/>

In my case the main imageComponent who would be doing all the rendering so I just want to figure out what is the natural way to pass in a list of attributes to a component.

+3  A: 
<i:imageComponent width="480" height="320" imageUrls="img1Url1, imgUrl2"
    imageCaptions="imageCaption1, imageCaptions2"/>

This design is error-prone because it requires that two separate lists be kept in sync.

<i:imageComponent width="480" height="320">
    <i:image id="im1" href="url1" caption="caption1"/>
    <i:image id="im2" href="url2" caption="caption2"/>
<i:imageComponent/>

This design is limiting because it requires the component consumer to define a fixed number of contained images. At least with the first design, the imageUrls and imageCaptions attributes can be bound to dynamic values using EL expressions.


Think about defining a model for your component - an interface that it can use to iterate over the values. For example, UIData (the component type underlying h:dataTable) uses a DataModel to handle its contents - see the spec for details.

This could result in a tag design like this:

<i:imageComponent width="480" height="320"
        value="#{backingBean.imageModel}" />

This approach requires less clutter in the view.


Instead of a model, consider a repeater design (which would rely on the user/developer providing the appropriate binding types):

<i:imageComponent width="480" height="320"
        value="#{backingBean.someIterable}" var="img" >
    <i:image href="#{img.href}" caption="#{img.caption}"/>
<i:imageComponent/>

This approach has the advantage of not requiring any special types in the back-end.

McDowell
I don't mind the repeater design but wouldn't that mean that I also have to define an "image" component?The problem I have is that the main "imageComponent" renderer is the one that needs to do all the rendering so it needs all the information including that specified in the image tags. Also the image tag would have no rendering to do - is this typical of components?
Having a component that does not render is OK (see h:column). See also UIComponent.getRendersChildren: http://java.sun.com/javaee/5/docs/api/javax/faces/component/UIComponent.html#getRendersChildren()
McDowell