NOTE: This is outdated information that applies only to Tapestry 4. For current information see http://tapestry.apache.org/input-validation.html.

If you need to generate a sequence of check boxes in a form, it can be tricky to work out in your form listener which check boxes have been selected. Here is my solution which involves reconstructing the list of check boxes when the value method of each @Checkbox component is called.

First create a Serializable object to hold the id of the check box:

package uk.co.wjrs.tapestry.util;

import java.io.Serializable;

public class CheckboxItem implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * Can be whatever you like - perhaps a primary key from a database
     */
    private Serializable id;

    private boolean selected;

    public Serializable getId() {
        return id;
    }

    public void setId(Serializable id) {
        this.id = id;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }

}

This class must be serializable because Tapestry will stringify the object and use it as the value of the input element in the html output.

Then create the datasource for your checkbox list. I have used a class with a static method for demonstration purposes, but you would normally pull some data out of a database to create the list.

package uk.co.wjrs.tapestry.util;

import java.util.ArrayList;
import java.util.List;

public class CheckboxItemFactory {

    public static List<CheckboxItem> getCheckboxItems() {
        List<CheckboxItem> items = new ArrayList<CheckboxItem>();

        {
            CheckboxItem item = new CheckboxItem();
            item.setId("ITEM1");
            items.add(item);
        }

        {
            CheckboxItem item = new CheckboxItem();
            item.setId("ITEM2");
            items.add(item);
        }

        {
            CheckboxItem item = new CheckboxItem();
            item.setId("ITEM3");
            item.setSelected(true);
            items.add(item);
        }

        return items;
    }

}

Then your Tapestry page class would be as follows. This page simply logs the values, but you could do whatever you like with them, e.g. put the values back into a db.

package uk.co.wjrs.tapestry.pages;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.tapestry.event.PageBeginRenderListener;
import org.apache.tapestry.event.PageEvent;
import org.apache.tapestry.html.BasePage;

import uk.co.wjrs.tapestry.util.CheckboxItem;
import uk.co.wjrs.tapestry.util.CheckboxItemFactory;

public abstract class MultipleCheckboxes extends BasePage implements
        PageBeginRenderListener {

    private static final Logger logger = Logger
            .getLogger(MultipleCheckboxes.class);

    public abstract void setCheckboxItems(List<CheckboxItem> checkboxItems);

    public abstract List<CheckboxItem> getCheckboxItems();

    public abstract void setUpdatedCheckboxItems(
            List<CheckboxItem> checkboxItems);

    public abstract List<CheckboxItem> getUpdatedCheckboxItems();

    public abstract void setCurrentItem(CheckboxItem item);

    public abstract CheckboxItem getCurrentItem();

    public void pageBeginRender(PageEvent pageEvent) {
        if (pageEvent.getRequestCycle().isRewinding()) {
            logger.info("Rewinding");
            setUpdatedCheckboxItems(new ArrayList<CheckboxItem>());

        } else {
            logger.info("Beginning full page render");

            if (getUpdatedCheckboxItems() == null) {
                setCheckboxItems(CheckboxItemFactory.getCheckboxItems());
            } else {
                setCheckboxItems(getUpdatedCheckboxItems());
            }
        }
    }

    public void doSubmit() {
        logger.info("Form submitted");
        for (CheckboxItem item : getUpdatedCheckboxItems()) {
            logger.info("Item " + item.getId() + " is "
                    + (item.isSelected() ? "" : "not ") + "selected");
        }
    }

    public boolean isCurrentItemSelected() {
        return getCurrentItem().isSelected();
    }

    public void setCurrentItemSelected(boolean selected) {
        CheckboxItem item = getCurrentItem();
        item.setSelected(selected);
        getUpdatedCheckboxItems().add(item);
    }

}

The html page is as follows.

<html>
<body>
<h1>Multiple Checkboxes</h1>
<p>

<form jwcid="@Form" listener="listener:doSubmit">
        <span jwcid="@For" source="ognl:checkboxItems" value="ognl:currentItem">
                <input jwcid="@Checkbox" value="ognl:currentItemSelected"></input><span jwcid="@Insert" value="ognl:currentItem.id"/><br/>
        </span>
        <input jwcid="@Submit" value="Submit"/>
</form>

</p>
</body>
</html>

The key to the solution is the setCurrentItemSelected method in the page class. A list of CheckboxItems is reconstructed during rewinding.

Tested on Tapestry 4.0.2.

Dynamically_Generated_Checkboxes (last edited 2011-01-02 01:48:46 by BobHarner)