You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by simon <si...@chello.at> on 2008/01/05 00:43:30 UTC

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

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
> >
> 


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