Korhonen, Kalle wrote:
Looks to me that you should use x:saveState to extend the lifetime of
the request scoped bean and/or to save the specific properties of the
bean - unless there is some specific reason why you are avoiding the use
of x:saveState?
I didn't know it existed. I've looked at some of the examples on its
use and I'm still not sure exactly what it does. It's not very well
documented from what I've been able to find. Care to fill me in on the
details of how to use it and what it does?
Thanks
Rich
Kalle
-----Original Message-----
From: Richard Wallace [mailto:[EMAIL PROTECTED]
Sent: Sunday, June 12, 2005 12:33 PM
To: MyFaces Discussion
Subject: Re: Filling in select lists
Martin Marinschek wrote:
have you tried to set the "immediate" attribute on the
ui-input component?
Yes. I have immediate="true" set for the <h:selectOneMenu>
elements and in the event handler I have it updating the
selected value and then jumping to the renderResponse() phase
to bypass validation. The problem is that the backing bean
is request scoped and the previously set value for the first
<h:selectOneMenu> does not get set again in the backing bean.
So the only way I can think to get that value is to use the
getExternalContext().getRequestParameterMap(). Here's the
JSF tags so you can get a better idea of what is going on
cause I don't think I'm getting my thoughts across very clearly.
<h:panelGroup>
<h:outputLabel for="organization"
value="Organization" />
<h:selectOneMenu id="organization"
value="#{courseHandler.selectedOrganization}"
valueChangeListener="#{courseHandler.handleOrganizationChanged}"
onchange="submit()" immediate="true">
<f:selectItem itemValue="" />
<f:selectItems
value="#{organizationHandler.organizationChoices}" />
</h:selectOneMenu>
</h:panelGroup>
<br />
<h:panelGroup>
<h:outputLabel for="department"
value="Department" />
<h:selectOneMenu id="department"
value="#{courseHandler.selectedDepartment}"
valueChangeListener="#{courseHandler.handleDepartmentChanged}"
onchange="submit()" immediate="true">
<f:selectItem itemValue="" />
<f:selectItems
value="#{courseHandler.departmentChoices}" />
</h:selectOneMenu>
</h:panelGroup>
<br />
<h:panelGroup>
<h:outputLabel for="instructors"
value="Instructors" />
<h:selectManyListbox id="instructors"
value="#{courseHandler.selectedInstructors}">
<f:selectItems
value="#{courseHandler.contactChoices}" />
</h:selectManyListbox>
</h:panelGroup>
Now the selectItems for the department depend on the selected
value of the organization and the selectItems for the
instructors list depends on the selected value for the
departments. What's happening is that when a user selects
the organization the department list gets populated just
fine. When they select the department, the instructors list
gets populated fine, but the departments list comes up empty
because the value for the organization is never set in the
backing bean because the update model phase is also bypassed.
The only ways I can think to fix this is to make the backing
bean session scoped so that the selected organization is
persisted across requests. But that makes me nervous cause
it seems error prone. The only other way to do it is to use the
getExternalContext().getRequestParameterMap() and lookup the
value for the selected organization in the
handleDepartmentChanged() event handler. But that seems like
a bad idea because it means I have to know the id of the
element ahead of time, which I think is just sloppy design.
I'll probably wind up switching to a session scoped backing
bean if I have to. But that raises all sort of other
problems in other areas that I'm not entirely sure how to
work around. I guess I could move stuff that needs to be
request based like the dynamic choice elements to be request
scoped and keep the current working object session scoped or
something like that.
Does that sound like a decent approach or is there a better way?
Thanks again,
Rich
regards,
Martin
On 6/12/05, Richard Wallace <[EMAIL PROTECTED]> wrote:
I understand all that you've said and am using some
application scoped
beans for global select items that don't change. The
problem is that
the list of items that I'm working with now are database backed and
are likely to change often. I can maybe cache the top level select
list items, the organizations and update it when an organization is
added or updated. But the others, the list items for
departments and
personnel are dependent on the selected organization so
there's no way
to cache them.
What about my other questions? When the second select list, the
department, selected value changes and the page is submitted for
immediate event handling, it seems the only way to avoid validation
_and_ have the selected organization set in the backing bean is to
lookup the value myself using the
FacesContext.getExternalContext().getParameterMap(). Is there a
better way to accomplish this?
Thanks for the feedback,
Rich
Craig McClanahan wrote:
One thing to remember is that you are *not* limited to
referencing a
single backing bean. Using a request scope backing bean
corresponding to the page is fine ... but quite often, the
lists of
select items are fairly constant, and you'd *really* like to build
them only once, right?
In the Shale <http://struts.apache.org/shale> "use cases" example
application, there is an illustration of the technique I
prefer for
this ... bind select lists to a property on an application scoped
managed bean (if they are common to all users) or on a
session scoped
managed bean (if they are specific to a user). The
example includes
"select locale" use case, which includes a dropdown like this:
<h:selectOneListbox id="locale"
value="#{locale$select.locale}">
<h:selectItems value="#{domains.supportedLocales}"/>
</h:selectOneListbox>
where "locale$select" is my request scoped managed bean for this
page, and "domains" is an application scoped managed bean that
includes this
method:
public SelectItem[] getSupportedLocales();
Inside this method, you have a number of alternative strategies
available ... and you can change your choice without
callers having a
clue :-). Consider among other options:
* Lazily instantiating the list the first time someone
calls this method.
* Using a ServletContextListener to load up the appropriate data
before the first request is received.
* Either of the above two techniques, plus a timer thread to erase
the cached value after a given amount of time (to pick up the
changes that occasionally occur, without having to
restart the app).
* Either of the above two techniques, plus embedded logic
that does a
relatively cheap database access to determine whether the
data has
changed, and refreshes the list first.
Doing this sort of logic on every request is quite likely
a waste of
resources. Strive to minimize the number of times you do
things like
"create a SelectItems array containing the 50 state
abbreviations and
names" :-). That's the sort of thing I would want to do just once
:-).
Craig McClanahan
On 6/11/05, Richard Wallace <[EMAIL PROTECTED]> wrote:
I just thought that I should also mention that my backing
bean is a
request scoped object. So another solution is to switch
this to a
session based backing bean, but my backing bean is where
the select
items for organizations, departments and contacts for the
list boxes
and drop-down menus are generated. I would like to be
able to cache
those for the life of the request but they shouldn't be cached
across requests since they could change at any time.
What's the best practice for these backing beans? My design is
pretty much following the design ideas in a couple of
articles I've
read where the backing bean contains the current selected
object and
the JSF pages bind with
value="#{contactHandler.currentContact.firstName}" for
example. Is
it better to have this backing bean be session scoped or
request scoped?
Richard Wallace wrote:
Richard Wallace wrote:
So what do I need to do to fix this? One idea is to
try and find
the value that JSF will use in the form and use that if
there is
one and then otherwise use the backing beans value when I'm
generating the department choices. Seems kind of hacky since
that's one of the things that JSF is supposed to do for you is
provide the form values. I'm also not certain how to get the
values that JSF is going to use in the forms without
having it update the model values.
Well, I figured this part out at least. I can use the
FacesContext.getExternalContext ().getRequestParameterMap(), but
then I'd need to know the key of the form and form element to be
able to lookup the value. Obviously, not an ideal solution.
Another idea is if I can somehow avoid doing the
validation some
other way. That's really the only reason I need to do
the event
processing right away and then skip to the rendering
phase. But
I've looked and there doesn't seem to be another way of
bypassing validation.
Well, I've looked around and this doesn't seem possible.
Unless I
can do something with PhaseListeners, but I don't see how.
Please help!
Thanks,
Rich