Jim Driscoll's Blog

Notes on Technology and the Web

JSF 2.0: Writing fully reusable Spinner Component

leave a comment »

In my previous blog postings, I talked about making the Spinner component, and then added styles via an external css file. Please review those first, if you haven’t looked at them yet.


This time, we’ll move the JavaScript out to a separate file, and make sure that we can execute multiple spinners in a page, like this:

            <ez:spinner value="#{multinumber.number1}" increment="1" id="spinner1" />
            <ez:spinner value="#{multinumber.number2}" increment="10" id="spinner2" />

Now, we’ve changed the implementation of the component to this (I’ve marked the parts we’ll discuss in bold):

<composite:implementation>
    <h:outputStylesheet name="spinner/spinner.css" />
    <h:outputScript name="ajax.js" library="javax.faces" target="head"/>
    <h:outputScript name="spinner/spinner.js" target="head" />
    <script type="text/javascript">
        init("#{compositeComponent.clientId}","#{compositeComponent.attrs.increment}");
    </script>
    <h:inputText id="number" value="#{compositeComponent.attrs.value}" styleClass="spinnerText"/>
    <h:panelGroup id="spinnerButtonPanel" styleClass="spinnerButtons">
        <h:commandButton id="forward"  value="ʌ" styleClass="spinnerButton"
                         onclick="return changeNumber('#{compositeComponent.clientId}',1);" />
        <h:commandButton id="back" value="v" styleClass="spinnerButton"
                         onclick="return changeNumber('#{compositeComponent.clientId}',-1);" />
    </h:panelGroup>
</composite:implementation>

Going through the important bits of this file, we have:


  • A call to load an external javascript file
  • A function invocation of an init function, passing two values that will be substituted in at the time the page is sent to the client. Note that, as in the previous example, I’ve wrapped these values in quotation marks, since they’re really just text in a page.
  • And lastly, we have two onclick handlers, both of which call another function, passing in the clientId of the component, as well as what direction the spinner should turn. Again, the clientId of the component is substituted at the time the page is sent to the browser, so the Javascript never actually sees the EL, just text on a page.

Now, we’ll take a look at that external JavaScript code.

if (!window["spinnerIncrement"]) {
    var spinnerIncrement = {};
}
function init(componentID, increment) {
    spinnerIncrement[componentID] = Number(increment);
    if (isNaN(spinnerIncrement[componentID]) || spinnerIncrement[componentID] == 0 ) {
        spinnerIncrement[componentID]= 1;
    }
}

function changeNumber(componentID, amount) {
    var entry = document.getElementById(componentID+":"+"number");
    var val = Number(entry.value);
    if (isNaN(val)) { val = 0; }
    entry.value = val + (amount * spinnerIncrement[componentID]);
    return false;
}

So, why do we do all this odd looking componentID passing? Because we want this file to be used by multiple components – and that means setting up some sort of namespace to store variables for each component. The way I’m showing here is just one possible way, but it works with a fairly short number of lines. Let go through the logic:


  • First, we check if spinnerIncrement exists, and create it if it does not.
  • Then, in init, we associate the value of the increment with the componentID of each component. Init will be called once per component, as we saw above.
  • Lastly, for each onclick, we modify the value of the text input field, as we’ve done in the prior two Spinner examples. The only difference is that we’re now aware of the componentID of the calling component, and we’re using it as a context for all our persistent variables.

Again, a simple trick, and now you can use multiple ajax aware components in a page.


As always, questions welcome – and remember, you can try these examples out in the new Glassfish v3 prelude release, if you use JSF 2.0.


I’ll continue to build on these examples in future blogs, but for now, I think we’ve taken the spinner component about as far as it can go.

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

Advertisements

Written by jamesgdriscoll

February 9, 2010 at 8:05 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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

%d bloggers like this: