Jim Driscoll's Blog

Notes on Technology and the Web

JSF 2.0: Writing a Spinner component

leave a comment »

In a previous posting, I described the basic structure of a JSF 2.0 composite component.
Here’s a slightly more complex example of writing a component using JSF 2.0’s Composite Component feature. The Spinner component takes only 30 lines to create the classic “entry field with buttons” spinner as a component you can use in any JSF page.
First a description of what a “Spinner” is, in case you’ve never heard that name before. Put simply, it’s an input field, allowing you to type in (typically numeric) data, with a set of buttons to one side that let you increment that data with a button push. In our example, we’ll have an input field with four buttons arranged horizontally to it’s right. A better configuration would be to have the buttons vertical – but that will require a bit of css magic, so we’ll leave that for another time. Today, we’ll just discuss the basic logic of the component, we’ll make it pretty in a future post.
So, without further introduction, here’s the 30 lines you need to make a Spinner. I’ll fill you in on what’s happening in each line afterward.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml"
    <composite:attribute name="value" required="true" />
    <composite:attribute name="increment" required="false" />
    <h:inputText id="number" value="#{compositeComponent.attrs.value}"/>
    <h:commandButton id="bigback" value="<<" onclick="return changeNumber(-10);"/>
    <h:commandButton id="back" value="<" onclick="return changeNumber(-1);"/>
    <h:commandButton id="forward" value=">" onclick="return changeNumber(1);"/>
    <h:commandButton id="bigforward" value=">>" onclick="return changeNumber(10);"/>
    <script type="text/javascript">
        function changeNumber(amount) {
            var increment = Number("#{cc.attrs.increment}");
            if (isNaN(increment) || increment == 0 ) {
                increment = 1;
            var entry = document.getElementById("#{cc.clientId}"+":"+"number");
            entry.value = Number(entry.value) + (amount * increment);
            return false;

We’ll go through this line by line: Doctype and namespace declarations are unsurprising, just be sure to declare the “composite” namespace, as well as any other namespace that you’ll need for the components that you use (we need the core html namespace “h”, so we declare that too.
Next, we declare the interface of the component: in other words, the arguments you pass to it as attributes. We declare two: value, which will act just like the value in a an inputText tag, and increment, which will be an optional attribute that specifies how much the value changes when we press the buttons.
After that, we have the implementation section: This is the part that will be output into the using page, in a template-like fashion. For us, it’s essentially in two parts – the JSF components, and a little bit of JavaScript that they invoke.
The components are just standard JSF components, used in standard ways – one thing to note is that the inputText has a value which is set to an EL expression value="#{cc.attrs.value}" . As in my previous example, this just resolves to whatever is passed to the component’s tag’s value attribute. Since this is an input text, that value expression needs to be writable, so we’d call this tag with code that looked like:
<ez:spinner value=”#{number.number}” increment=”10″/>
Where number is a bean that has both setNumber and getNumber methods.
The buttons are typical JSF buttons that call Javascript. Since the Javascript function they call returns false, they never submit anything to the server- they just change the value of the inputText field with Javascript.
The Javascript itself has a couple of bits that are specific to this being inside a component: The first is this line:
var increment = Number(“#{cc.attrs.increment}”);
As you can see, we got EL right in the Javascript code. This EL substitutes out at runtime into the value of the increment attribute for the spinner tag. We wrap it in quotes and cast it to a number just to be safe, then test it. If it’s not a valid entry, we’ll use a default value.
The next interesting line is:
var entry = document.getElementById(“#{cc.clientId}”+”:”+”number”);
One of the trickier parts of using Javascript inside composite components is the fact that id values are dyamically generated at runtime – as they must be, since we may have this code more than once in the page. Dynamically created id’s are the only way to make sure that the id’s are unique in the page. So, we need to determine the id of any component we act on in a similar dynamic manner. The clientId will be set to the id of the component at runtime, and it will prepend all the id’s that you assign subcomponents, with a separator character in between. In the current implementation, “:” will always be that separator character, but for FCS, we’ll have to determine that dynamically too.
Lastly, here’s how to use this component in a page (just as a reminder):

  1. Put a reference to the composite component in your page – xmlns:ez=”http://java.sun.com/jsf/composite/spinner&#8221;
  2. Name your file as resources/spinner/spinner.xhtml
  3. Use a tag that looks like:<ez:spinner value=”#{number.number}” increment=”10″/>

And that’s all. Please feel free to ask questions… more examples to come.

(This article originally published on my java.net blog on November 8, 2008.)


Written by jamesgdriscoll

February 9, 2010 at 6:59 PM

Posted in ajax, JSF

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: