Richard Wallace wrote:
Richard Wallace wrote:
Hello,
I'm having another problem with my select list and the value changed
event listener. I have the following tag:
<h:selectManyListbox id="organizations"
value="#{contactHandler.selectedOrganizations}"
valueChangeListener="#{contactHandler.handleOrganizationChanged}"
onchange="submit()" immediate="true">
This is for an "Edit Contact" page so when the page is initially
loaded there is an organization selected. The problem that I'm
having is that when I click the update button to invoke the
appropriate action handler it is never called. The page just
reloads. If I click the update button a second time it does call the
action handler.
I did a trace of the phases with a PhaseListener and found that it is
jumping from the apply request values phase to the render response
phase. So I added some logging in the places I call the
FacesContext.renderReponse() method and lo and behold the
handleOrganizationChanged() event handler is being called in spite of
nothing on the page having been changed. To investigate further I
logged the events old value and the new value and found that the old
value was empty when it shouldn't have been.
Is this a side effect of the event handling being declared as being
immediate? What can I do to fix this?
Ok, I found the problem and it's entirely my fault. But it brings up
another question. Basically all my page backing beans are request
scoped and this is an edit page so I need to pass in the id of the
contact to edit. I did this in the getContact() accessor method which
checks if the contact is null and if it is gets the contact id from
the external context parameter map. This is all well and good when I
initially go into the edit page with the url
http://localhost:8080/contact/edit.jsf?contactId=11.
In the form I try and carry this through with a hidden form element
called contactId thinking that I should still be able to lookup the
external context parameter value for "contactId" and get the right
thing. That is, of course, wrong because the actual form element name
is like "_id1:contactId". So the reason it comes up with the empty
list of selected organizations is because it's using a newly
constructed object and not one loaded from the backend.
So now my question is what is the best way to carry the id across page
reloads like this? I've seen the method where you would have the
currentContactId be a JSF managed bean property and then pass in
param.contactId. But that runs into the same kind of problem. The
other method I've seen for doing this sort of thing is to make the
actual link the user clicks on to get to the page a <h:commandLink>
element bound to an option that sets the current contact in a session
scoped backing bean and then does a redirect to the actual edit page.
I don't like this for a number of reasons, one being the session
scoped backing bean and the other being that users can't bookmark the
URL. I'll have to discuss this with some people here to see if the
latter really is an issue or not, but I'd like to get the feedback of
people on the mailing list that have done this before. So, what's the
most commonly accepted practice on how to handle this? The session
scoped backing bean which wraps the actual data model object? Or is
there a better way?
Well I found a couple of solutions to this problem. I'm not sure either
is the best solution but they both seem to work well enough.
One solution was to add <x:saveState
value="#{contactHandler.selectedOrganizations}"> element. After doing
some testing it seems this causes the selectedOrganizations property to
be set in the restore values phase before even any immediate events are
handled. So it seems like it might be a good rule of thumb to use
<x:saveState> on any values that you need in the event handler.
In this case, however, the better solution was to use a a myfaces
extension and use <x:inputHidden id="contactId" forceId="true"> to make
sure the element has the name that the backing bean uses to load the
actual data object.
Rich
- Re: Errant event firing Richard Wallace
-