5 Replies Latest reply on Jun 23, 2008 5:57 PM by gjeudy

    c:set and JSF

    gjeudy

      Hi,


      I know this request might not be related as much to Seam but I noticed something strange with using c:set in a facelets page.


      I am using JSTL with facelets to derive some labels based on backing bean states.


      
      <c:choose>
      
                      <c:when test="${editMode}">
      
                              <c:choose>
      
                                      <c:when test="${staticEntity.id != null}">
      
                                              <c:set var="actionLabel" value="Edit #{type}" />
      
                                      </c:when>
      
                                      <c:otherwise>
      
                                              <c:set var="actionLabel" value="Add #{type}" />
      
                                      </c:otherwise>
      
                              </c:choose>
      
                      </c:when>
      
                      <c:otherwise>
      
                              <c:set var="actionLabel" value="Show #{type}" />
      
                      </c:otherwise>
      
              </c:choose>
      
              <h:outputText value="${actionLabel}" styleClass="label" />



      When I add a new entity the h:outputText in the page will render 'Add Product' for example. When i save the product (JSF postback), the product gets persisted and now the h:outputText should show 'Edit Product' but it still shows 'Add Product'. If I leave the page and come back to it for the same product then the h:outputText correctly displays 'Edit Product'.


      I read something, don't remember where, c:set should be avoided because it is a compile time tag as opposed to render time.


      As I understand all JSF tags are render time. JSTL c:set happens to be compile time which means the value of c:set is only evaluated when a new JSF component tree is built.


      Since this is view layer logic I would hate to have to set a label on my action bean just so my page can pick up the latest value.


      I could use the primitive below approach but I figure there must be a more elegant way to solve this.


      
      <h:outputText rendered="#{editMode and staticEntity.id == null}" value="Add #{type}" styleClass="label" />
      
      <h:outputText rendered="#{editMode and staticEntity.id != null}" value="Edit #{type}" styleClass="label" />
      
      <h:outputText rendered="#{!editMode}" value="Show #{type}" styleClass="label" />



      Any ideas?

        • 1. Re: c:set and JSF
          amitev
          <h:outputText value="#{(editMode and staticEntity.id == null)?'Add'?'Edit' type}" />


          • 2. Re: c:set and JSF
            wrzep

            Guillaume Jeudy wrote on Jun 20, 2008 20:58:

            I read something, don't remember where, c:set should be avoided because it is a compile time tag as opposed to render time.


            Here? :)



            I could use the primitive below approach but I figure there must be a more elegant way to solve this.

            <h:outputText rendered="#{editMode and staticEntity.id == null}" value="Add #{type}" styleClass="label" />
            <h:outputText rendered="#{editMode and staticEntity.id != null}" value="Edit #{type}" styleClass="label" />
            <h:outputText rendered="#{!editMode}" value="Show #{type}" styleClass="label" />



            I guess there is a lot of ways to do it... For example, why not to create additional Seam component that provides this Show/Add/Edit value?
            Or, another solution:


            value="#{!editMode ? 'Show' : (empty staticEntity.id ? 'Add' : 'Edit')} #{type}"
            




            -Pawel

            • 3. Re: c:set and JSF
              gjeudy

              Thanks Guys,


              Didn't know I could use a ternary if operator in EL expressions. I guess I should read up on this more.


              The idea of creating a small Seam component to handle Show/Add/Edit value sounds like a good idea if I have to reuse this in many parts in my view layer during a single request cycle.


              I'm not used to think that small as far as components go :)


              Pawel.. right on facelets dev guide, shame on me and my failing memory, needed a refresher :-).

              • 4. Re: c:set and JSF
                dan.j.allen

                Look in the FAQ of this site for some great starting points on the EL.


                c:set should be avoided because it just doesn't fit with the way that JSF works (not because it is inherently broken). There are two alternatives to using c:set.


                Option 1: Use Facelets compositions with ui:param to pass values into a template. Of course, this works if you are nesting the logic rather than setting a variable in the same block level.


                Option 2: Leverage the JBoss EL! You can call pretty much any method, which means that you can do something like the following:


                #{eventContext.set('varname', 'value')}



                #{eventContext.set('label', 'Edit '.concat(type))}

                • 5. Re: c:set and JSF
                  gjeudy

                  Thanks Dan for your contribution to this post.


                  I prefer Option1 as it seems more elegant to me. But yeah JBoss EL is powerful do I fear it could complexify the view layer unnecessarily if abused.


                  BTW I ordered your book on amazon. Can't wait to get it after all the positive reviews I heard.