In my previous two technical posts, I described a "switchlist", then added Ajax behavior using the f:ajax tag. If you haven't already, please go back and check on those posts to catch up to where we are.

Today, we'll take that basic Switchlist (not the Ajaxified one), and turn it into a component that you can drop into your page with a single tag. We'll Ajaxify the Switchlist compoenent once we've got it stuffed into a component. Now, we've already covered writinga simple composite component, as well as writing a number of more complex examples. We won't cover that material again, so you may want to review all of that before we start.

Done? Good. Let's get started.

First, as usual, let's look at what the tag will look like when we're done:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ez="http://java.sun.com/jsf/composite/switchlist">
<h:head>
    <title>Switchlist Example</title>
</h:head>
<h:body>
        <h1>Switchlist Example</h1>
        <h:form id="form1">
             <ez:switchlist id="switchlist" selected1="#{listholder.list1}"
                                            selected2="#{listholder.list2}"
                                            items1="#{listholder.items1}"
                                            items2="#{listholder.items2}"
                                            move1to2="#{listholder.move1to2}"
                                            move2to1="#{listholder.move2to1}"/>
            <br/>
            <h:commandButton value="reload" type="submit"/>
            <h:messages/>
        </h:form>
</h:body>
</html>

Well, that's a lot of parameters, but there isn't really any way around that - the tag needs to juggle two lists (which needs 4 parameters), and two buttons (which needs two parameters). The parameters will still point to the same bean properties that we saw in the first post on switchlist.

As in other composite components, we sayxmlns:ez="http://java.sun.com/jsf/composite/switchlist">, which is really saying "look in the resources directory, and find the directory switchlist". Then since the tag is "switchlist", it's a reference to resources/switchlist/switchlist.xhtml. Here's the full contents of that file, we'll go through the relevant parts line by line:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:composite="http://java.sun.com/jsf/composite">
<head>
    <title>This will not be present in rendered output</title>
</head>
<body>
<composite:interface name="switchlist"
                     displayName="Switchlist Component"
                     shortDescription="A basic example of the composite component feature">

    <composite:attribute name="selected1" required="true"/>
    <composite:attribute name="selected2" required="true"/>
    <composite:attribute name="items1" required="true"/>
    <composite:attribute name="items2" required="true"/>
    <composite:attribute name="move1to2" targets="move1to2" required="true" method-signature="void f1(javax.faces.event.ActionEvent)" />
    <composite:attribute name="move2to1" targets="move2to1" required="true" method-signature="void f2(javax.faces.event.ActionEvent)" />
</composite:interface>

<composite:implementation>
    <h:outputStylesheet name="switchlist/switchlist.css"/>
    <h:selectManyListbox value="#{compositeComponent.attrs.selected1}" styleClass="switchlist">
        <f:selectItems value="#{cc.attrs.items1}"/>
    </h:selectManyListbox>
    <h:panelGroup id="buttonGroup" styleClass="switchlistButtons">    
    <h:commandButton id="move1to2" value="&gt;&gt;" actionListener="#{cc.attrs.move1to2}" styleClass="switchlistButton"/>
    <h:commandButton id="move2to1" value="&lt;&lt;" actionListener="#{cc.attrs.move2to1}" styleClass="switchlistButton"/>
    </h:panelGroup>
    <h:selectManyListbox value="#{cc.attrs.selected2}" styleClass="switchlist">
        <f:selectItems value="#{cc.attrs.items2}"/>
    </h:selectManyListbox>
</composite:implementation>
</body>
</html>

Since the new bits are the most important, I'll cover wiring the buttons up. That happens in two places. The first is in defining the interface, when we say:

composite:attribute name="move1to2" targets="move1to2" required="true" method-signature="void f1(javax.faces.event.ActionEvent)"

We define the name of the attribute (move1to2), the target of the attribute (move1to2), which in our example is named the same, but doesn't have to be - it's the id of the button that has the actionListener.

Then we define the signature of the method that that named id will call, in this case, void f1(javax.faces.event.ActionEvent) - which is just the method signature for any function that's called by an actionListener event. This is the markup that informs the composite component handler that there's a method value, rather than a value expression, contained in the #{cc.attrs.move1to2}expression that we put on that button.

A little wordy, but easy enough to understand once you've seen it done.

The rest of the example just uses the same kinds of markup that we've already seen done on other composite components.

In my next post, I'll cover wiring this up to use Ajax - and I'll be going back to using the jsf.ajax JavaScript API, since I'd like to add a few extra features above what we've already done.

As always, if you've got questions on how this all works, please ask below.