Search |
||
A final look at the Switchlist JSF 2 componentPosted by driscoll on May 26, 2009 at 6:19 PM PDT
It's been a long time, but I've revisited the Switchlist component I blogged about here here and here. Read through those old entries to see where we are with things. I will assume you're already familiar with the content of those entries, we've got a lot to cover as it is.
Today, we're going to completely rework this code, to illustrate some best practices. We'll make the component use Ajax, we'll have it separate out the control from the model, and we'll make the whole component addressable with an Ajax tag itself as well. First, the change in the backing Java classes. Previously, I'd just tossed together all the of the necessary functions into a single monolithic Java class, which exposed four data properties (which means 8 getters and setters), as well as two action methods, used in an action listener. For obvious reasons, this is a sloppy design. Better to have the data separated out, with the control methods hidden from the enduser.
With that in mind, we'll create an interface, let's call it ListHolder. It looks like this:
So, now we've got the model and the controller all laid out, let's see how this would be used in a view. Here's the tag we'd like to use in the using page:
Now, let's look at the interface in the composite component itself:
And lastly, let's take a look at the implementation.
First, wrap everything in a div, and give it an id that's the same as the composite component as a whole. This is something you'll need to do to let ajax tags operate on your component - otherwise, there won't be anything in your page with the id of the component you just added - in our case "switchlist", in the using page. There would only be "switchlist:buttonGroup" and such. Doing this also means that you can better do styling with css, since you now have a block you can work with, instead of a loose group of tags with no wrapper.
Next, see that we have a bunch of references that look like Also, note that we've changed from using an actionListener attribute on the buttons, to an action. We're also passing values into the controller via the f:setPropertyActionListener - these two things are related. If we'd just continued to use the actionListener method of executing a method, the setPropertyActionListeners wouldn't be called until after the actionListener - which makes sense, since those listeners are called in the order they're added, but not terribly useful for our purposes. So we instead use a action, which returns null - meaning no navigation.
Lastly, note that for making this ajax enabled, we simply need to say: So, a brief recap:
Lots of code in a short space, but we've already covered a lot in other blogs. Questions? Ask away, in the comments, and I'll do my best to answer. And, one last note: If you're attending JavaOne, this example is the basis for a talk that Ryan Lubke and I will be giving at JavaOne - BOF 4146, on Wednesday, at 745pm, Esplanade 307. Come on by and ask questions. I'll post the slides and the full example code in a later blog, after the conference. »
Related Topics >>
Web Applications Comments
Comments are listed in date ascending order (oldest first)
Submitted by wbervoets on Thu, 2009-05-28 08:33.
Thanks for the tip where to find the PDL docs (eg. https://javaserverfaces.dev.java.net/nonav/rlnotes/2.0.0/index.html for 2.0beta1). I was looking in the spec :-)
I just updated to mojarra jsf2.0 beta1 on my Glassfish v3 and will dive into the composite: PDL documentation.
Wim
Submitted by wbervoets on Thu, 2009-05-28 07:43.
Hi Jim,
Thanks for your usefull blogposts about JSF2. I'm currently looking into composite components.
Here is my example:
I had a question about the . Is the only supported child element?
From reading older posts on Ed Burns blog I have also seen the following possibilities:
-
-
-
-
- .. other behavioural interfaces??
Are these deprecated or still available in current version of JSF2?
At least seems to work ok in Mojarra 2.0b12
Now I'm trying :
But then how can I access this "loginAction" in my composite component. I have:
but then I receive:
The class 'LoginManagedBean' does not have the property 'doLogin'.
I have seen the syntax:
That does work; but to me the method-signature seems more verbose/difficult?
Wim
Submitted by wbervoets on Thu, 2009-05-28 07:46.
Hmm, the site has eaten all my JSF example code; second try:
Hi Jim,
Thanks for your usefull blogposts about JSF2. I'm currently looking into composite components.
Here is my example:
<lp:loginBox userName="#{loginBean.userId}"
password="#{loginBean.password}"
loginAction="#{loginBean.doLogin}">
I had a question about the <composition:interface>. Is <composite:attribute> the only supported child element?
From reading older posts on Ed Burns blog I have also seen the following possibilities:
- <composite:actionSource>
- <composite:valueHolder>
- <composite:facet>
- <composite:editableValueHolder>
- .. other behavioural interfaces??
Are these deprecated or still available in current version of JSF2?
At least <composite:editableValueHolder> seems to work ok in Mojarra 2.0b12
Now I'm trying <composite:actionSource>:
<composite:actionSource name="loginAction" />
But then how can I access this "loginAction" in my composite component. I have:
<h:commandButton id="login" type="submit" action="#{cc.attrs.loginAction}" value="Login" styleClass="button"/>
but then I receive:
The class 'LoginManagedBean' does not have the property 'doLogin'.
I have seen the syntax:
<composite:attribute name="loginAction" targets="login" required="true" method-signature="String f1()" />
That does work; but to me the method-signature seems more verbose/difficult?
Wim
Submitted by driscoll on Thu, 2009-05-28 08:15.
You'll find the information you're looking for - documentation on all the composite namespace elements - in what are called the PDL docs. You can find the PDL docs linked off of the release notes - if you look back a couple posts, you'll see that we annouced beta1 (which is b13) - so you should revisit our website download section anyway. The PDL (Page Definition Language) docs cover all the f: tags, h: tags, composite: tags and ui: tags, as well as c: and fn: from JSTL. Many parts of the docs have small examples as well. These are just as important as JavaDoc, so you should get used to looking there.
If you still have questions after that, you can always post them to our webtier@glassfish.dev.sun.com mailing list.
Also, your question makes me realize I should write a blog hitting each of the elements, and their use. That will have to happen after JavaOne.
Submitted by cayhorstmann on Mon, 2009-07-20 06:49.
Hi Jim: How does this technique work when you have more than one switchlist component on the page? Wouldn't each of them access the same SwitchlistController?
Submitted by driscoll on Mon, 2009-07-20 09:44.
Cay -
The controller is requestscoped - and since you can only manipulate one list set per request (via ajax), there are as a result no concurrency issues. Even if you abandon ajax, it should still work, since the list controller isn't accessed unless you hit the button which moves things from one list to the other. Hitting "submit" somewhere else on the page just submits the current values of each list, without moving them anywhere.
You still have to create two listholders for each switchlist in the page, of course - but that's to be expected, since you're operating on different datasets, otherwise, why have more than one component?
Submitted by cayhorstmann on Wed, 2009-07-22 08:13.
Thanks Jim. Actually, it works much better when you replace
<:setPropertyActionListener value="#{listholder1}" target="#{switchlistController.listHolder1}"/>
with
<f:setPropertyActionListener value="#{cc.attrs.listholder1}" target="#{switchlistController.listHolder1}"/>
:-)
The key observation is that what you call a "controller" must be stateless so that it can serve requests from any component instance. Since the latest Glassfish build supports action method parameters, you can say sayonara to the sPAL tags and rewrite the example as
<h:commandButton id="move2to1" value="<<" action="#{switchlistController.m2_1(cc.attrs.listholder1, cc.attrs.listholder2)}"/>
Submitted by driscoll on Wed, 2009-07-22 09:14.
Um, whoops. Yes, you're of course right - the reference to #{listholder} in the setProp will blow up the minute you really try to reuse it. I've fixed this bug in my blog, and in the associated demo.
One clarification - the controller (why the quotes BTW?) needs to have request scope, rather than none scope (which would be truely stateless), since it's actually having it's state primed for that request by the setProp calls - though as you point out, method parameters should also allow @NoneScoped to be used, as well as a cleaner API.
|
||
|
|