You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by M Rather <mr...@definedlogic.com> on 2007/12/13 21:56:35 UTC

c:if test not evaluating properly in ui:repeat and t:dataTable

Hello,

I have a  jsf, myfaces, facelets, tomahawk, displaytag and c:forEach 
question. My apologies if you see this question in some other boards 
relevant to this discussion.

This is the issue.

I load a list of customers.. I loop  thru each of  them  using  
c:forEach, ui:repeat, displaytag and t:dataTable. All of them behave 
differently, if <c:if test is used inside the body tag.. All of them are 
incorrect except for c:forEach (there may be a different problem with 
display tag, as I can't get it to show up in this page.)

Below is the code for the page.. and the result follows it. The code is 
self explanatory and the results show the discrepancy. I would 
appreciate if someone could point out what I may be doing wrong, or if I 
am not understanding how t:dataTable or ui:repeat works... Are there 
issues with c:if evaluation at compile time versus runtime? Is there any 
remedy to this?

Thanks
MRather

customerList.xhtml
===============================CODE BEGIN
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:c="http://java.sun.com/jstl/core"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:t="http://myfaces.apache.org/tomahawk"
    xmlns:acegi="http://sourceforge.net/projects/jsf-comp/acegijsf"
    xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
    xmlns:display="http://displaytag.sf.net">


    <ui:composition>
        <c:set var="customers" value="${customerList.customers}" 
scope="request" />
       
        ==================== c:forEach =================<br/>
        <c:forEach var="customer" items="${customers}" >
            <c:set var="isOneC" value="NO" />
            <c:if test="${customer.id eq 1}">
                <c:set var="isOneC" value="YES" />
            </c:if>
            ${customer.id} - ${customer.name} - ${isOneC}
            <br/>
        </c:forEach>
        ==================== c:forEach =================<br/><br/><br/>
       
       
        ==================== ui:repeat =================<br/>
        <ui:repeat var="customer" value="${customers}" >
            <c:set var="isOneUI" value="NO" />
            <c:if test="${customer.id eq 1}">
                <c:set var="isOneUI" value="YES" />
            </c:if>
            ${customer.id} - ${customer.name} - ${isOneUI}
            <br/>
        </ui:repeat>
        ==================== ui:repeat =================<br/><br/><br/>
       
        ==================== display:table =================<br/>
        <display:table name="${customers}" />
        ==================== display:table =================<br/><br/><br/>
       
        ==================== t:dataTable =================<br/>
        <t:dataTable var="customer" value="${customers}" >
            <t:column styleClass="#{row.styleClass}">
               
                <c:set var="isOneT" value="NO" />
                <crt:if test="${customer.id eq 1}">
                    <c:set var="isOneT" value="YES" />
                </crt:if>
               
                ${customer.id}   - ${isOneT}
            </t:column>
            <t:column styleClass="#{row.styleClass}">
                ${customer.name}
            </t:column>
        </t:dataTable>
        ==================== t:dataTable =================<br/><br/><br/>
       
       
        <ui:debug />
    </ui:composition>
</html>
==========================================CODE END

and below is the result. c:forEach works, but others don't


==================== c:forEach =================RESULT BEGIN
1 - cust1- YES
2 - cust2 - NO
3 - cust3 - NO
4 - cust4- NO
5 - cust5 - NO
6 - cust6 - NO
7 - cust7 - NO
8 - cust8 - NO
9 - cust9- NO
==================== c:forEach =================


==================== ui:repeat =================
1 - cust1- NO
2 - cust2 - NO
3 - cust3 - NO
4 - cust4- NO
5 - cust5 - NO
6 - cust6 - NO
7 - cust7 - NO
8 - cust8 - NO
9 - cust9 - NO
==================== ui:repeat =================


==================== display:table =================
==================== display:table =================


==================== t:dataTable =================
1 - YES    cust1
2 - YES    cust2
3 - YES    cust3
4 - YES    cust4
5 - YES    cust5
6 - YES    cust6
7 - YES    cust7
8 - YES    cust8
9 - YES    cust9
==================== t:dataTable =================RESULT END




Re: invoking a managed bean inside a loop for another managed bean's call

Posted by M Rather <mr...@definedlogic.com>.
Thanks Simon for your revised feedback.

I still feel that making a managed-bean call in an iterator still 
satisfies separation of view from model. I think its an issue of
how JSF builds components and how it uses a value derived in an 
iterator, or I have not understood that well yet.

In any case, I managed to resolve my issue a bit differently. Here is 
how, for those who may access this thread later on.

This was the original scenario, where the inner call to 
#{officeBean.offices} would not take iterated value #{customer.id} from 
#{customerBean.customers}

<ui:repeat var="customer" value="#{customerBean.customers}" >
  Customer: #{customer.id} - #{customer.name} -
   <ui:repeat var="office" value="#{officeBean.offices}">
       Office: #{office.id}
   </ui:repeat>
</ui:repeat>

So, on my 'customerBean' I added another method called 
#{customerBean.officesByCustomers} which loads all offices for the 
customers returned by #{customerBean.customers}, and returns a map, with 
key as customer and values as a list of offices.

And, in the pseudo-code repeater I used it like this:

<ui:repeat var="customer" value="#{customerBean.customers}" >
  Customer: #{customer.id} - #{customer.name} -
   <ui:repeat var="office" 
value="#{customerBean.officesByCustomers[customer.id]}">
       Office: #{office.id}
   </ui:repeat>
</ui:repeat>

Works as expected.
The drawback is that customerBean is pretty loaded up, but I guess that 
guarantees the complete separation of view from service.

NOTE: this message is getting rejected by myfaces email server.. so I'm 
not attaching any response form previous threads in this email ..

Thanks
MRather

Re: invoking a managed bean inside a loop for another managed bean's call

Posted by simon <si...@chello.at>.
On Sat, 2008-01-05 at 00:43 +0100, simon wrote:
> JSF presentation layouts (jsp pages, facelets pages, etc) are not meant
> to be programming languages. They are meant only to select specific
> parts of a model for presentation to the user.
> 
> But EL isn't designed for invoking backing bean methods *passing* data
> from the "customers model"; that is crossing the border from "selecting
> data from the model" into a generic computing language.

In hindsight, I may have been a little too simplistic with my earlier
reply. It *is* a good idea to avoid logic in pages, and to restrict them
to just selecting data for display. But sometimes function calls with
parameters *are* useful.

You don't mention which version of JSF you are using.

There is a wiki page here about passing parameters when using JSF1.1:
  http://wiki.apache.org/myfaces/Parameters_In_EL_Functions

I believe it is *much* easier in JSF1.2 (which uses the new "unified
EL"). However I haven't used that myself, so someone else will have to
provide the details on that.

Regards,

Simon



Re: invoking a managed bean inside a loop for another managed bean's call

Posted by simon <si...@chello.at>.
Hi,

JSF presentation layouts (jsp pages, facelets pages, etc) are not meant
to be programming languages. They are meant only to select specific
parts of a model for presentation to the user.

So asking a backing bean for the "customers model" is fine. And
iterating over list-typed properties of the "customers model" is fine. 

But EL isn't designed for invoking backing bean methods *passing* data
from the "customers model"; that is crossing the border from "selecting
data from the model" into a generic computing language.

So you might want to rethink your approach here. If you really cannot
present a static model for the EL to pull data from, then the return
object from #{customerBean.customers} could be your own smart wrapper
class, rather than the actual model object. Then it can offer methods
that can be called via #{customer.offices} rather than trying to do a
method call officebean.offices(customer). But pause before doing this:
the fact that it isn't easy is perhaps telling you that you haven't got
the model-view-controller separation right.

Regards,

Simon

On Fri, 2008-01-04 at 18:27 -0500, M Rather wrote:
> Hello,
> 
> A similar problem as discussed in this thread.
> 
> How is the following possible in JSF: (note, read the code below as 
> pseudo code..., a ui:repeat could be a t:dataTable)
> 
> <ui:repeat var="customer" value="#{customerBean.customers}" >
>    Customer: #{customer.id} - #{customer.name} -
>     <ui:repeat var="office" value="#{officeBean.offices}">
>         Office: #{office.id}
>     </ui:repeat>
> </ui:repeat>
> 
> where officeBean.offices should take #{customer.id} as a property. So 
> for each customer displayed, display that customers' offices.
> 
> When I define officeBean as managed bean with a property for customerId, 
> I see that for all customers the same id is sent (i.e. the first one). I 
> think it is similar to the issue discussed before in this thread, that 
> when the component is built with the values are bound at that time. The 
> resolution at that time was to use 'rendered' attribute for components, 
> but how can we resolve this issue where another managed-bean's method 
> needs to be invoked in a loop and the current value in the loop needs to 
> be provided as a porperty for inner invoked method?
> 
> I also tried to define the inner manged bean with scope of 'none', 
> assuming that for each invocation it will be created and it will pickup 
> the value at that instant.. but I get the following exception:
> 
> Property [propertyName] references object in a scope with shorter 
> lifetime than the target scope none
> 
> Thanks
> MRather
> 
> 
> M Rather wrote:
> > Thanks Andrew,
> >
> > I got the desired output using the rendered attribute. Though I will 
> > test out limitRendered tag as well, I am getting some compile errors 
> > on 1.1.7 sandbox snapshot (mvn dependencies).
> >
> > For those who might see this thread, below is the code that works..
> >
> > ==================== ui:repeat with rendered=================<br/>
> >        <ui:repeat var="customer" value="${customers}" >
> >            ${customer.id} - ${customer.name} -
> >            <ui:fragment rendered="#{customer.id eq 1}">
> >              YES
> >            </ui:fragment>
> >            <ui:fragment rendered="#{customer.id ne 1}">
> >              NO
> >            </ui:fragment>
> >            <br/>
> >        </ui:repeat>
> >        ==================== ui:repeat with 
> > rendered=================<br/><br/><br/>
> >
> > and this is the generated result, as desired
> >
> > ==================== ui:repeat with rendered=================
> > 1 - cust1- YES
> > 2 - cust2 - NO
> > 3 - cust3 - NO
> > 4 - cust4 - NO
> > 5 - cust5 - NO
> > 6 - cust6 - NO
> > 7 - cust7 - NO
> > 8 - cust8 - NO
> > 9 - cust9 - NO
> > ==================== ui:repeat with rendered=================
> >
> > -MRather
> >
> 


invoking a managed bean inside a loop for another managed bean's call

Posted by M Rather <mr...@definedlogic.com>.
Hello,

A similar problem as discussed in this thread.

How is the following possible in JSF: (note, read the code below as 
pseudo code..., a ui:repeat could be a t:dataTable)

<ui:repeat var="customer" value="#{customerBean.customers}" >
   Customer: #{customer.id} - #{customer.name} -
    <ui:repeat var="office" value="#{officeBean.offices}">
        Office: #{office.id}
    </ui:repeat>
</ui:repeat>

where officeBean.offices should take #{customer.id} as a property. So 
for each customer displayed, display that customers' offices.

When I define officeBean as managed bean with a property for customerId, 
I see that for all customers the same id is sent (i.e. the first one). I 
think it is similar to the issue discussed before in this thread, that 
when the component is built with the values are bound at that time. The 
resolution at that time was to use 'rendered' attribute for components, 
but how can we resolve this issue where another managed-bean's method 
needs to be invoked in a loop and the current value in the loop needs to 
be provided as a porperty for inner invoked method?

I also tried to define the inner manged bean with scope of 'none', 
assuming that for each invocation it will be created and it will pickup 
the value at that instant.. but I get the following exception:

Property [propertyName] references object in a scope with shorter 
lifetime than the target scope none

Thanks
MRather


M Rather wrote:
> Thanks Andrew,
>
> I got the desired output using the rendered attribute. Though I will 
> test out limitRendered tag as well, I am getting some compile errors 
> on 1.1.7 sandbox snapshot (mvn dependencies).
>
> For those who might see this thread, below is the code that works..
>
> ==================== ui:repeat with rendered=================<br/>
>        <ui:repeat var="customer" value="${customers}" >
>            ${customer.id} - ${customer.name} -
>            <ui:fragment rendered="#{customer.id eq 1}">
>              YES
>            </ui:fragment>
>            <ui:fragment rendered="#{customer.id ne 1}">
>              NO
>            </ui:fragment>
>            <br/>
>        </ui:repeat>
>        ==================== ui:repeat with 
> rendered=================<br/><br/><br/>
>
> and this is the generated result, as desired
>
> ==================== ui:repeat with rendered=================
> 1 - cust1- YES
> 2 - cust2 - NO
> 3 - cust3 - NO
> 4 - cust4 - NO
> 5 - cust5 - NO
> 6 - cust6 - NO
> 7 - cust7 - NO
> 8 - cust8 - NO
> 9 - cust9 - NO
> ==================== ui:repeat with rendered=================
>
> -MRather
>


Re: c:if test not evaluating properly in ui:repeat and t:dataTable

Posted by M Rather <mr...@definedlogic.com>.
Thanks Andrew,

I got the desired output using the rendered attribute. Though I will 
test out limitRendered tag as well, I am getting some compile errors on 
1.1.7 sandbox snapshot (mvn dependencies).

For those who might see this thread, below is the code that works..

==================== ui:repeat with rendered=================<br/>
        <ui:repeat var="customer" value="${customers}" >
            ${customer.id} - ${customer.name} -
            <ui:fragment rendered="#{customer.id eq 1}">
              YES
            </ui:fragment>
            <ui:fragment rendered="#{customer.id ne 1}">
              NO
            </ui:fragment>
            <br/>
        </ui:repeat>
        ==================== ui:repeat with 
rendered=================<br/><br/><br/>

and this is the generated result, as desired

==================== ui:repeat with rendered=================
1 - cust1- YES
2 - cust2 - NO
3 - cust3 - NO
4 - cust4 - NO
5 - cust5 - NO
6 - cust6 - NO
7 - cust7 - NO
8 - cust8 - NO
9 - cust9 - NO
==================== ui:repeat with rendered=================

-MRather

Re: c:if test not evaluating properly in ui:repeat and t:dataTable

Posted by Andrew Robinson <an...@gmail.com>.
Also, I wrote this:

http://myfaces.apache.org/sandbox/limitRendered.html

On Dec 13, 2007 2:02 PM, Andrew Robinson <an...@gmail.com> wrote:
> c:... are evaluated at compile time
> all others are evaluated at render time.
>
> Best suggestion is to never use jstl tags with JSF. If you must,
> understand that they are executed *before* the components are built.
> There are WIKIs out there on this.
>
> Use the rendered attribute instead of c:if
>
>
> On Dec 13, 2007 1:56 PM, M Rather <mr...@definedlogic.com> wrote:
> > Hello,
> >
> > I have a  jsf, myfaces, facelets, tomahawk, displaytag and c:forEach
> > question. My apologies if you see this question in some other boards
> > relevant to this discussion.
> >
> > This is the issue.
> >
> > I load a list of customers.. I loop  thru each of  them  using
> > c:forEach, ui:repeat, displaytag and t:dataTable. All of them behave
> > differently, if <c:if test is used inside the body tag.. All of them are
> > incorrect except for c:forEach (there may be a different problem with
> > display tag, as I can't get it to show up in this page.)
> >
> > Below is the code for the page.. and the result follows it. The code is
> > self explanatory and the results show the discrepancy. I would
> > appreciate if someone could point out what I may be doing wrong, or if I
> > am not understanding how t:dataTable or ui:repeat works... Are there
> > issues with c:if evaluation at compile time versus runtime? Is there any
> > remedy to this?
> >
> > Thanks
> > MRather
> >
> > customerList.xhtml
> > ===============================CODE BEGIN
> > <html xmlns="http://www.w3.org/1999/xhtml"
> >     xmlns:c="http://java.sun.com/jstl/core"
> >     xmlns:f="http://java.sun.com/jsf/core"
> >     xmlns:h="http://java.sun.com/jsf/html"
> >     xmlns:ui="http://java.sun.com/jsf/facelets"
> >     xmlns:t="http://myfaces.apache.org/tomahawk"
> >     xmlns:acegi="http://sourceforge.net/projects/jsf-comp/acegijsf"
> >     xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
> >     xmlns:display="http://displaytag.sf.net">
> >
> >
> >     <ui:composition>
> >         <c:set var="customers" value="${customerList.customers}"
> > scope="request" />
> >
> >         ==================== c:forEach =================<br/>
> >         <c:forEach var="customer" items="${customers}" >
> >             <c:set var="isOneC" value="NO" />
> >             <c:if test="${customer.id eq 1}">
> >                 <c:set var="isOneC" value="YES" />
> >             </c:if>
> >             ${customer.id} - ${customer.name} - ${isOneC}
> >             <br/>
> >         </c:forEach>
> >         ==================== c:forEach =================<br/><br/><br/>
> >
> >
> >         ==================== ui:repeat =================<br/>
> >         <ui:repeat var="customer" value="${customers}" >
> >             <c:set var="isOneUI" value="NO" />
> >             <c:if test="${customer.id eq 1}">
> >                 <c:set var="isOneUI" value="YES" />
> >             </c:if>
> >             ${customer.id} - ${customer.name} - ${isOneUI}
> >             <br/>
> >         </ui:repeat>
> >         ==================== ui:repeat =================<br/><br/><br/>
> >
> >         ==================== display:table =================<br/>
> >         <display:table name="${customers}" />
> >         ==================== display:table =================<br/><br/><br/>
> >
> >         ==================== t:dataTable =================<br/>
> >         <t:dataTable var="customer" value="${customers}" >
> >             <t:column styleClass="#{row.styleClass}">
> >
> >                 <c:set var="isOneT" value="NO" />
> >                 <crt:if test="${customer.id eq 1}">
> >                     <c:set var="isOneT" value="YES" />
> >                 </crt:if>
> >
> >                 ${customer.id}   - ${isOneT}
> >             </t:column>
> >             <t:column styleClass="#{row.styleClass}">
> >                 ${customer.name}
> >             </t:column>
> >         </t:dataTable>
> >         ==================== t:dataTable =================<br/><br/><br/>
> >
> >
> >         <ui:debug />
> >     </ui:composition>
> > </html>
> > ==========================================CODE END
> >
> > and below is the result. c:forEach works, but others don't
> >
> >
> > ==================== c:forEach =================RESULT BEGIN
> > 1 - cust1- YES
> > 2 - cust2 - NO
> > 3 - cust3 - NO
> > 4 - cust4- NO
> > 5 - cust5 - NO
> > 6 - cust6 - NO
> > 7 - cust7 - NO
> > 8 - cust8 - NO
> > 9 - cust9- NO
> > ==================== c:forEach =================
> >
> >
> > ==================== ui:repeat =================
> > 1 - cust1- NO
> > 2 - cust2 - NO
> > 3 - cust3 - NO
> > 4 - cust4- NO
> > 5 - cust5 - NO
> > 6 - cust6 - NO
> > 7 - cust7 - NO
> > 8 - cust8 - NO
> > 9 - cust9 - NO
> > ==================== ui:repeat =================
> >
> >
> > ==================== display:table =================
> > ==================== display:table =================
> >
> >
> > ==================== t:dataTable =================
> > 1 - YES    cust1
> > 2 - YES    cust2
> > 3 - YES    cust3
> > 4 - YES    cust4
> > 5 - YES    cust5
> > 6 - YES    cust6
> > 7 - YES    cust7
> > 8 - YES    cust8
> > 9 - YES    cust9
> > ==================== t:dataTable =================RESULT END
> >
> >
> >
> >
>

Re: c:if test not evaluating properly in ui:repeat and t:dataTable

Posted by Andrew Robinson <an...@gmail.com>.
c:... are evaluated at compile time
all others are evaluated at render time.

Best suggestion is to never use jstl tags with JSF. If you must,
understand that they are executed *before* the components are built.
There are WIKIs out there on this.

Use the rendered attribute instead of c:if

On Dec 13, 2007 1:56 PM, M Rather <mr...@definedlogic.com> wrote:
> Hello,
>
> I have a  jsf, myfaces, facelets, tomahawk, displaytag and c:forEach
> question. My apologies if you see this question in some other boards
> relevant to this discussion.
>
> This is the issue.
>
> I load a list of customers.. I loop  thru each of  them  using
> c:forEach, ui:repeat, displaytag and t:dataTable. All of them behave
> differently, if <c:if test is used inside the body tag.. All of them are
> incorrect except for c:forEach (there may be a different problem with
> display tag, as I can't get it to show up in this page.)
>
> Below is the code for the page.. and the result follows it. The code is
> self explanatory and the results show the discrepancy. I would
> appreciate if someone could point out what I may be doing wrong, or if I
> am not understanding how t:dataTable or ui:repeat works... Are there
> issues with c:if evaluation at compile time versus runtime? Is there any
> remedy to this?
>
> Thanks
> MRather
>
> customerList.xhtml
> ===============================CODE BEGIN
> <html xmlns="http://www.w3.org/1999/xhtml"
>     xmlns:c="http://java.sun.com/jstl/core"
>     xmlns:f="http://java.sun.com/jsf/core"
>     xmlns:h="http://java.sun.com/jsf/html"
>     xmlns:ui="http://java.sun.com/jsf/facelets"
>     xmlns:t="http://myfaces.apache.org/tomahawk"
>     xmlns:acegi="http://sourceforge.net/projects/jsf-comp/acegijsf"
>     xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
>     xmlns:display="http://displaytag.sf.net">
>
>
>     <ui:composition>
>         <c:set var="customers" value="${customerList.customers}"
> scope="request" />
>
>         ==================== c:forEach =================<br/>
>         <c:forEach var="customer" items="${customers}" >
>             <c:set var="isOneC" value="NO" />
>             <c:if test="${customer.id eq 1}">
>                 <c:set var="isOneC" value="YES" />
>             </c:if>
>             ${customer.id} - ${customer.name} - ${isOneC}
>             <br/>
>         </c:forEach>
>         ==================== c:forEach =================<br/><br/><br/>
>
>
>         ==================== ui:repeat =================<br/>
>         <ui:repeat var="customer" value="${customers}" >
>             <c:set var="isOneUI" value="NO" />
>             <c:if test="${customer.id eq 1}">
>                 <c:set var="isOneUI" value="YES" />
>             </c:if>
>             ${customer.id} - ${customer.name} - ${isOneUI}
>             <br/>
>         </ui:repeat>
>         ==================== ui:repeat =================<br/><br/><br/>
>
>         ==================== display:table =================<br/>
>         <display:table name="${customers}" />
>         ==================== display:table =================<br/><br/><br/>
>
>         ==================== t:dataTable =================<br/>
>         <t:dataTable var="customer" value="${customers}" >
>             <t:column styleClass="#{row.styleClass}">
>
>                 <c:set var="isOneT" value="NO" />
>                 <crt:if test="${customer.id eq 1}">
>                     <c:set var="isOneT" value="YES" />
>                 </crt:if>
>
>                 ${customer.id}   - ${isOneT}
>             </t:column>
>             <t:column styleClass="#{row.styleClass}">
>                 ${customer.name}
>             </t:column>
>         </t:dataTable>
>         ==================== t:dataTable =================<br/><br/><br/>
>
>
>         <ui:debug />
>     </ui:composition>
> </html>
> ==========================================CODE END
>
> and below is the result. c:forEach works, but others don't
>
>
> ==================== c:forEach =================RESULT BEGIN
> 1 - cust1- YES
> 2 - cust2 - NO
> 3 - cust3 - NO
> 4 - cust4- NO
> 5 - cust5 - NO
> 6 - cust6 - NO
> 7 - cust7 - NO
> 8 - cust8 - NO
> 9 - cust9- NO
> ==================== c:forEach =================
>
>
> ==================== ui:repeat =================
> 1 - cust1- NO
> 2 - cust2 - NO
> 3 - cust3 - NO
> 4 - cust4- NO
> 5 - cust5 - NO
> 6 - cust6 - NO
> 7 - cust7 - NO
> 8 - cust8 - NO
> 9 - cust9 - NO
> ==================== ui:repeat =================
>
>
> ==================== display:table =================
> ==================== display:table =================
>
>
> ==================== t:dataTable =================
> 1 - YES    cust1
> 2 - YES    cust2
> 3 - YES    cust3
> 4 - YES    cust4
> 5 - YES    cust5
> 6 - YES    cust6
> 7 - YES    cust7
> 8 - YES    cust8
> 9 - YES    cust9
> ==================== t:dataTable =================RESULT END
>
>
>
>