2

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?

mweber
  • 107
  • 1
  • 9

1 Answers1

1

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:

Community
  • 1
  • 1
Aritz
  • 30,971
  • 16
  • 136
  • 217
  • 1
    Well explained, that did the trick! Unfortunately I ran into another problem. I'll open a new question about it. – mweber Aug 24 '16 at 14:16
  • More to the point, putting an `ui:repeat` between the `b:carousel` and its `b:courouselItems` modifies the HTML ids of the items. I didn't check whether the client-side widget copes with the modified ids, but many widgets don't. Even worse, the JSF tree looks different than BootsFaces expects. It sees a `ui:repeat`. This component is silently ignored. The `b:carouselItem` is the child of `ui:repeat` - or the grandchild of `b:carousel`. We didn't teach BootsFaces to care about grandchildren yet. Plus, the children of `ui:repeat` are rendered during the render phase - to late for BootsFaces. – Stephan Rauh Aug 25 '16 at 19:13
  • @Xtreme Biker: Maybe you'll want to rephrase the first sentence of your answer. The rest of your answer is correct. `b:carousel` expects static content, so the solution if to modify the JSF tree - and that's what JSTL tag does. – Stephan Rauh Aug 25 '16 at 19:17
  • @StephanRauh I think it is what is said, but feel free to edit my answer however you want! – Aritz Aug 25 '16 at 19:26
  • Do you see my edit already? Currently, it's waiting for peer review. I hope you like the edit. – Stephan Rauh Aug 25 '16 at 20:03