When I teach my JSF crash course to my software engineering students, everyone nods, works through the lab, and I don't hear any JSF issues from them for a couple of weeks. Then they run into sPAL.
They'll have some link, usually in a data table, that needs to send some information about itself to a managed bean. And they can't figure out how to do it. I can never remember it either because it is so unintuitive, so I look it up in Core JSF.
Before JSF 1.2, you had to smuggle the value into an attribute or (gasp) a parameter child component:
<h:commandLink actionListener="#{backingBean.doSomething}"> <f:attribute name="rowId" value="#{row.id}" /> </h:commandLink>
Then you had to fish it out with a series of API call that only a mother could love (and that tied your bean to the JSF API):
public class BackingBean { public void doSomething(ActionEvent event) { String rowId = (String) event.getComponent().getAttributes().get("rowId"); do something with rowId } }
Blecch.
This was slightly improved in JSF 1.2, with the addition of the sPAL tag:
<h:commandLink action="#{backingBean.doSomething}"> <f:setPropertyActionListener target="#{data.id}" value="#{row.id}"/> </h:commandLink>
The tag causes a property to be set in your managed bean. You are no longer tied to the JSF API, but you must add a field and a property setter:
public class BackingBean { private String rowId; public void setId(String rowId) { this.rowId = rowId; } public String doSomething() { do something with rowId return null; } }
Ugh.
As of today, the days of blecch and ugh are over. You can now specify parameters in method expressions, like this:
<h:commandLink action="#{backingBean.doSomething(#{row.id})">
Here is the backing bean:
public class BackingBean { public String doSomething(String rowId) { do something with rowId; return null; } }
This fixes issue 1149 and is available in build 56 of Glassfish v3.
Sayonara sPAL!