Friday, November 09, 2007

H:SelectOneMenu

This is the JSF tag that causes me more frustration than just about any other tag.   Probably documented the worst - probably a relation ship there...

So here is an example of the tag:

 

<h:selectonemenu value="#{selectManager.selectedTheme}">
<a4j:support actionlistener="#{treeManager.filterWorkspaces}"
ajaxsingle="true"
rerender="workspaceTree"
event="onchange">
<f:selectitems value="#{selectManager.themes}">
</h:selectonemenu>

 


Aside from from the a4j:support tag (we'll talk about that later) it is pretty much a text book example. The problem is what happens in the selectManager. 


We have 2 values we are binding to this component one is the #{selectManager.selectedTheme} and the other is #{selectManager.themes}.  If we take a step back and remember what the HTML select/option guys do we can figure out what is going on the selectedTheme variable is going to be one Object that is submitted on the post - the tricky part is that the themes object supposedly can be a List, an Array , a Set but really you just want to use a List.  Everything else just causes problems.


So the data backing the selectOneMenu is kind of important.  The API and documentation says that you need to use SelectItem objects and when you create a new one it takes an Object and a String (there are other constrcutors but this one works good for me)in it's constructor one is the value the other is the label.  Fair enough...


Here is the really important part the Object for the value really needs to be a String.  Now you can go and jump through all kinds of hoops to write converters and modify all your config files but just make the darn thing a String and be done with it.  If you want to put in your fancy objects I wish you the best of luck but keep the complex stuff in your code not the transmission between the jsps and your controllers.


So, the a4j:support part... this is the fancy stuff that is given to us from ajax4jsf library it makes your select component make ajax calls to the bound listener (#{treeManager.filterWorkspaces}) in our case.  It submits to a method that needs to accept an ActionEvent and return nothing.  Once you get into that method it is super easy to get the selected item - notice the selectOneMenu has a bound value #{selectManager.selectedTheme} that value is updated via the DHTML it has nothing to do with AJAX or form submits anytime you change the select list that value is changed... So when you're in your event method all you have to do is ask the FacesContext what the value is something like this:

SelectManager mgr = (SelectManager)FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("selectManager");
mgr.getSelectedTheme();

 


That's it... Pretty easy huh?


-Aaron

No comments: