Search code examples
jsfcarouseluirepeatbootsfaces

Use ui:repeat with b:carousel?


Environment:

I'm working with JSF2.2, Bootsfaces 0.9.1, Primefaces 6.0, JEE7 and Hibernate 5.2 in combination with MySQL 5.7 DB.

What I have:

I've got a model which has a set of images. The set contains instances of my custom Image class which holds values for the Image like a title, description and the filename.

The images are stored on the filesystem and I got the MySQL DB for storing the models. I tried to display images on a view in my webapp and everything works fine. I also displayed some images with b:carousel tag from bootsfaces and everthing worked like I expected.

What I tried to do:

The next step I tried was to use for displaying a set of images with a different size. The following code was my attempt to realize this:

<b:carousel id="carousel" style="width: 800px; height: 400px;">
    <ui:repeat value="#{modelDetailBean.modelImages}" var="img">
         <b:carouselItem>
              <b:image value="#{modelDetailBean.getImage(img)}"/>
         </b:carouselItem>
    </ui:repeat>
</b:carousel>

I recognized that no images got displayed in my carousel. Then I added at least 1 fixed to see if it's working and recognized that all images of the set are present in the carousel however the carousel doesn't take them into account correctly.

My main question:

Is it possible to use the ui:repeat tag to populate a carousel?

If it's possible: How can I do that? What am I doing wrong here?

If it's not: Which alternatives do I have to realize this with JSF and without a lot of javascript and so on?


Solution

  • Basically, the b:carousel component expects static items, but ui:repeat renders them dynamically. The solution is to shift the generation of the b:carouselItems to an early JSF lifecycle phase.

    JSF performs its lifecycle in phases and the one taking care of rendering the response is the last one (it's pretty well explained in the links below). The key point here is that you could still use JSTL, which is a tag handler and not a component and performs at view build time. So, basically, replacing your ui:repeat by c:forEach should solve your issue:

    <b:carousel id="carousel" style="width: 800px; height: 400px;">
        <c:forEach items="#{modelDetailBean.modelImages}" var="img">
             <b:carouselItem>
                  <b:image value="#{modelDetailBean.getImage(img)}"/>
             </b:carouselItem>
        </c:forEach>
    </b:carousel>
    

    This trick used to bring developers into trouble with the PARTIAL_STATE_SAVING in older Mojarra JSF versions (2.1.18 and previous), but not anymore. Anyway, always keep in mind JSTL acts before components are evaluated. From the link below:

    Use JSTL tags only to control flow of JSF component tree building. Use JSF UI components to control flow of HTML output generation. Do not bind the var of iterating JSF components to JSTL tag attributes. Do not rely on JSF events in JSTL tag attributes.

    Alternatively, forgetting about the b:carousel component, you could use JSF as a mere HTML generator and generate the required HTML to display a carousel using plain Bootstrap, as it is explained in the Do it yourself section of the docs.

    See also: