Monday, June 16, 2008

Wow...

I know the title of this blog entry seems a little weird, but after the odd experience I just had with ADF, all I could say was "wow".

The sequence is long and drawn out, but I will try to recount the steps:
1. I was experiencing what I think is a bug with dialogs and the partial page rendering on a return from a dialog interacting with af:selectOneChoice within an af:table. After you return from the dialog, all your drop-down lists get cleared of their current value for some reason.
2. I took this as a bug and decided to try to work around it.
3. I discovered that even though the value of the list would clear, the underlying value the list was based on was still there. This explains why other components (like af:inputText, af:outputText, etc) show their values just fine after returning back from a dialog and doing a PPR.
4. So I thought, why not use javascript to reset the selected value of the list?
5. Then I found out af:selectOneChoice manifests its options tag with sequential values even if you give it other values programatically by basing the selectOneList on a list of SelectItem's...with non-sequential values. In otherwords if you look at "View Source" (in IE parlance) at a select list generated by an af:selectOneChoice, you will always see the value attribute in the option tag say 1, 2, 3, 4, 5, ... regardless what you may have done in your backing bean. So if you created an ArrayList of a single SelectItem(new Integer(5), "five"), the HTML would come out ...at least: that was my experience. I am reasonably sure that is what happens. I would have been really pleased if that is *not* what happens...so I worked it for a while.
6. I then discovered the plain-ol' JSF component f:selectOneMenu (the counterpart to af:selectOneChoice in the ADF Faces world). This produces HTML, the value of which matches the SelectItem you create to back it up...so...
7. You can reset the values with JavaScript...
8. That was almost the end of my ordeal, except that I also found an old trick I used on tables from Steve Muench does not work in this scenario. Have you ever used something like the following as a value binding in a list's value property?

#{<backingbeanname>.<hashmapname>[row.<attribute>]}

Angle brackets (<>) are a meta descriptor.

I think this is from Muench example 71.

When you pass a value in with the square brackets, you can override the "get" method of the HashMap (anonymously, I think it's called) so that, although your presentation component (i.e., the drop-down list) is saying that its f:selectItems sub-component has a HashMap to back it up, it actually has whatever the overridden "get" method returns to back it up.

9. Only trouble is...f:selectOneMenu is not that smart. It thinks this is a HashMap backing this f:selectItems up. af:selectOneChoice does not have a problem with this, but we can't use that component here, right?

10. So we use an approach that creates some List attributes in the backing bean to make accessor functions for.

At any rate, this gives us our list. And when you return from a dialog and the value is reset you can write javascript to reset the selected value to a hidden field which contains the value it should be set to, and which uses af:hiddenField with a value of #{row.whateverFKyouneed}

:-)

3 comments:

ahnim said...

Hi, Do you have any solution for No 5 (selectOneChoice)? I'm looking for the answer too..

Michael A. Fons said...

Ahnim, welcome to my blog. :-)
A main point of this post is to tell what I did about #5. I used f:selectOneMenu instead. That will allow you to have the SelectItem value in the HTML instead of the sequence. If you need more information please tell me what you can and I will respond.

Suncat2000 said...

The way I understood the <af:selectOneChoice> is that if you set the "valuePassThru" attribute to true, then the value it stores is the <af:selectItem> option's "value" attribute instead of the index (anecdotal evidence says this doesn't work with <af:selectItems> though).
This suggestion sounds like a simpler solution than what you had to go through, if I read your objective right. I feel your pain.