Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Excerpt
:
hidden
=
true
}excerpt

How to add a variable/run-time-determined number of components

Panel
borderStylesolid
titleTable of contents
Table of Contents
minLevel1

= Repeaters =

e.g. A ListView in core or a number of components in the

Code Block
wicket-extensions repeaters

package.

maxLevel2

A A repeater is Wicket's way of doing loops and allows the user to add a series of items
or components where the number of items is not available at design-time.

...

.

The most common repeater is wicket.ListView, but there are also a number of components in the wicket-extensions' repeaters package.

FAQ

Q1. I added behavior to the ListView but I do not see its results in the output. Why?
Q2. I called ListView#setRenderBodyOnly(false) but the enclosing tags are still generated. How come?
Q3. My validation messages are cleared. What did I do?

A1 and A2: When you want to change the default generated markup it is important to realise that the ListView instances does not correspond to any markup but the generated ListItems do. This means that methods like Component#setRenderBodyOnly(boolean) and Component#add(IBehavior) should be invoked on the ListItem that is given in the ListView#populateItem(ListItem) method.

A3: See section below on repeaters and form components.

A quick introduction

Code:

Code Block
{panel}
    List list = Arrays.asList(new String[] { "a", "b", "c" });
    ListView listview = new ListView("listview", list) {
    {
{panel}
	    protected void populateItem(ListItem item)
	 {
        {
		    item.add(new Label("label", item.getModel()));
	        }
{panel}
    };
{panel}

Markup:

Code Block
<span wicket:id="listview">
{panel}
   this label is: <span wicket:id="label">label</span><br/>
{panel}
</span>

will Will result in the following redering rendered to the browser:

Code Block
<span wicket:id="listview">
   this label is: <span wicket:id="label">a</span><br/>
</span><span wicket:id="listview">
   this label is: <span wicket:id="label">b</span><br/>
</span><span wicket:id="listview">
   this label is: <span wicket:id="label">c</span><br/>
</span>

Using form components in a repeater

You can also put formcomponents into anything in the repeaters, you bind their values through IModel repeater, including FormComponents. You can bind values to the form components through IModels just as if they were in a regular form.

...

There are however a few provisions you have to take care of when using a repeater in the form. Usually repeaters clear out their items at the beginning of every request, when inside a form this is usually undesirable because you want to preserve the old items because you want them to keep their state as opposed to being recreated fresh.

For example, if you use ListView, for example, has you should call ListView.setReuseItems(true); which should be called when inside the form so that it preserves old items instead of always creating new ones everytime.

ListView Table Example

Lets take a simple example, we want to show a table of users:

Code Block
<table>
{panel}
  <tr wicket:id="listview">
    <td><span wicket:id="firstname"></span></td><td><spantd>
    <td><span wicket:id="lastname"></span></td>
  </tr>
{panel}
</table>

<p>
What we want is everything within

...

<tr>...</tr>

...

to repeat once for every user, so we attach ListView to the

...

tr

...

tag.

</p><p>
What ListView does is make its immediate children believe that their markup is that of the ListView itself, so each immediate child believes that it is attached to the <tr wicket:id="listview"> tag.
</p>

We need to represent these immediate ListView children with a container component, because each of these children may contain multiple children of its own, in our case the firstname/lastname labels. This is what the listitem ListItem is, its a simple WebMarkupContainer created for you so you don't have to do it everytime yourself.

So we will have a listitem ListItem container created for every list item in the list that feeds the listview. but this is not enough, as each of these listitems list items must contain the components that represent data within it (the firstname, lastname labels that we want to add).

This is where populateItem #populateItem(ListItem) comes in, it . It is called once for every listitem created and allows you to add components to it, so the listview render process looks like this:

...

Before each

...

render:

...

  1. clear all children
  2. for every list item in the list:
  3. create a ListItem webmarkupcontainer
  4. add created ListItem as a child
  5. call populateItem with the created ListItem container to allow users to populate it

During render:

  1. render all immediate children with own markup

In this example you just write:i.e. you just write...

Code Block
add(new ListView("listview", listuserList)
 {
	    protected void populateItem(ListItem item)
	 {
		        User user = (User) item.getModelObject();
		        item.add(new Label("firstname", user.getFirstname()));
		        item.add(new Label("lastname", user.getLastname()));
	    }
});

Example Details

In this example,

Code Block
User

The variable userList is initialized as follows:

Code Block

  List list = Arrays.asList(
    new User[] {
        new User("FirstA", "LastA"),
        new User("FirstB", "LastB"),
        new User("FirstC", "LastC")
      });

where class User is defined as a simple java bean is defined as:

Code Block
{panel}
  class User
  {
    String _first, _last;
{panel}

{panel}
    public User(String _first, String _last) {
    {
      this._first = _first;
        this._last = _last;
    }
{panel}

{panel}
    public String getFirstname() { return _first; }
    public String getLastname() { return _last; }
  }
{panel}

and the (java.util.List )

Code Block
list

is initialised as follows:

Optimizing the example with PropertyListView

When you are ok with using reflection, you can optimize the example by using PropertyListView. This works as follows:

List list = Arrays.asList( new User[]
{
    protected void 
new User("FirstA", "LastA"),
populateItem(ListItem item) {
        item.add(new 
User
Label("
FirstB", "LastB"),
firstname"));
        item.add(new 
User
Label("
FirstC", "LastC")
lastname"));
    
}
});
Code Block

add(new PropertyListView("listview", userList) 
Panel
Wiki Markup

This works because the model of each ListItem is wrapped in a CompoundPropertyModel.

...

Added by Gwyn 11:26, 8 May 2006 (BST) but Igor Vaynberg did all the hard workl I just copied from his mailing list posts!based on a post of Igor Vaynberg. Edited by Erik van Oosten to add the FAQ and PropertyListView example, and remove the wiki conversion mess.