Korhonen, Kalle wrote:
-----Original Message-----
From: Richard Wallace [mailto:[EMAIL PROTECTED]
Subject: Re: Filling in select lists
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?
With x:saveState you can store a value an object/property and restore it
using the same id, i.e. on "edit user" page you have x:saveState
id="editedUser" value="currentUser" (if currentUser is the name of your
user bean). Then on "confirm user changes" page you use the same tag to
restore the changed bean. The same goes for saving bean properties. Play
with it and see how it works.
Kalle
That worked perfectly! It was exactly the right magic I needed. Thanks
a ton!
Rich
-----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