GitHub

User guideModels

Bind components to a JavaBean

Read and write bean properties with PropertyModel, and let form fields find their property by id with CompoundPropertyModel.

How-toWicket 10 and later

Use property models when you bind many components to properties of one object, most often the fields of a form. They name the property with a string, a property expression. For a single property, lambda models do the same with compile-time checks.

The examples bind to this bean, held in a personModel of type IModel<Person>:

Person.java

public class Person implements Serializable {
    private String name;
    private String email;
    private Address address;
    private Person spouse;
    private List<Person> children;
    private Map<String, String> phones;

    // getters and setters
}

Bind one component with PropertyModel

PropertyModel reads and writes one property of an object or of a model’s object:

add(new Label("name", new PropertyModel<>(personModel, "name")));
add(new Label("spouseName", PropertyModel.of(personModel, "spouse.name")));

When the first argument is a model, the property model reads the property of that model’s current object, and detaches that model when it is detached itself. Pass a model rather than the bean, so the bean is not stored with the page.

PropertyModel uses the getter and setter when they exist and falls back to the field, private fields included. Reading is null-safe: when a step in the path is null, getObject() returns null.

Write a property expression

Expression Resolves to
name getName() and setName(), or the field name
address.city getAddress().getCity(); on write, an Address is created when it is null and has a default constructor
children.0.name or children[0].name the name of the first element of a list or array
phones.home or phones[home] the value for key home in a map
fullName() the result of calling the method fullName()

A property that does not exist fails when the model is first used, with a WicketRuntimeException such as “Property could not be resolved for class: … expression: …”. The compiler does not check the string, and renaming a property in your IDE does not update it.

Bind a form with CompoundPropertyModel

Give the form a CompoundPropertyModel and leave the fields without a model. Each field then binds to the property named by its id:

EditPersonPage.java

Form<Person> form = new Form<>("form", new CompoundPropertyModel<>(personModel)) {
    @Override
    protected void onSubmit() {
        personService.save(getModelObject());
    }
};
form.add(new TextField<>("name"));
form.add(new EmailTextField("email"));
form.add(new TextField<>("address.city"));
form.add(new Label("spouse.name"));
add(form);

EditPersonPage.html

<form wicket:id="form">
    <input type="text" wicket:id="name">
    <input type="email" wicket:id="email">
    <input type="text" wicket:id="address.city">
    <span wicket:id="spouse.name"></span>
    <button type="submit">Save</button>
</form>

This works through model inheritance: a component created without a model asks its parents for an IComponentInheritedModel, and CompoundPropertyModel answers with a property model that uses the component’s id as the expression. The fields do not have to be direct children of the form: Wicket walks up the parents until it finds an inheritable model, so containers in between do not get in the way.

The compound model can wrap a model, as above, or an object with CompoundPropertyModel.of(person). Wrap a model when the object comes from a database, so that it is loaded per request.

Use an id that differs from the property

When the id cannot be the property name, for example because two components show the same property, bind explicitly with bind:

CompoundPropertyModel<Person> model = new CompoundPropertyModel<>(personModel);
Form<Person> form = new Form<>("form", model);
form.add(new TextField<String>("partner", model.bind("spouse.name")));

bind returns a property model on the same object, for any component that needs one, inside or outside the form.

Give a field its own model inside the form

A component that has a model of its own does not inherit. Pass a model to the field and it ignores the form’s compound model:

form.add(new TextField<>("name"));                                           // inherits "name"
form.add(new TextField<>("nickname", LambdaModel.of(personModel,
        Person::getNickname, Person::setNickname)));                         // its own model
form.add(new CheckBox("subscribe", Model.of(false)));                         // not a Person property

Model classes describes the other property-based models, such as ComponentPropertyModel.