Overview

Wicketopia supports two types of component factories, viewer factories and editor factories. A viewer factory is used to generate components for read-only viewing of a property. An editor factory is used to generate components for editing a property. Luckily (actually by design) the component factories implement the same interface, so they can be used interchangeably depending upon the desired view. When creating property components, you must do so within a certain context.

Contexts

A Context, is used to define the "context" (hence the name) in which an operation is taking place. Each context has a name, (defined by a String of course) and there are four default context names, CREATE, UPDATE, VIEW, and LIST, defined as constants on the Context class. Users can also come up with their own context names (like "REGISTER" or "LOGIN") to suit their needs. A Context can also have attributes associated with it. They are stored using a map keyed by a type-safe MetaDataKey, similar to the way you assign metadata to Wicket components. The context of an operation helps Wicketopia figure out which components should be visible, enabled, or required (among other things). A context is used by the component factories to generate a property-configured component at runtime.

Using Component Factories

To use a component factory, we simply create one and ask it to generate components for us:

Manually-Constructed Form (Java Code)...

IModel<Person> model = new Model<Person>(new Person());
Form<Person> form = new Form<Person>("form", model);
// Create a factory...
PropertyComponentFactory<Person> editorFactory = Wicketopia.get().createEditorFactory(Person.class);
// Establish a context...
Context context = new Context(Context.CREATE);
// Create the label...
form.add(editorFactory.createPropertyLabel("nameLabel", "name"));
// Create an "editor" for the "name" property...
form.add(editorFactory.createPropertyComponent("nameEditor", model, "name", context));

Here, we're asking Wicketopia to create an editor component factory for the Person class. We set up a CREATE context, which means we're creating a new Person object. Then, we use the factory to create a label for the "name" property. Finally, we ask the factory to create an editor for the "name" property. Notice that we could easily change this code to generate a read-only view of our Person object by merely asking Wicketopia to create a viewer component factory as opposed to an editor component factory. Our markup would look something like:

Manually-Constructed Form (Markup)...

<form wicket:id="form">
  <table>
    ...
    <tr>
      <th><div wicket:id="nameLabel" /></th>
      <td><div wicket:id="nameEditor" /></td>
    </tr>
    ...
  </table>
</form>

Notice that we use <div> elements to position our generated components. This is part of the "contract" we have with Wicketopia. Since we don't know what type of component Wicketopia is going to generate, we can't reliably use a specific element type (some components insist that they are attached to the proper element type in the markup) in our markup. We must use generic element types supported by Wicket Panels. One caveat to this approach is that whenever a new property is added to the Person class and we want to display it on our form, we have to make sure we set up the new label/component for that property. To avoid this, we use a dynamic layout!

Using Dynamic Layouts

A "layout" component will automatically generate labels/components for all currently-visible fields in their order based on the bean class' metadata. For our Person class:

Dynamically-Generated Form...

Form<Person> form = new Form<Person>("form", model);
PropertyComponentFactory<Person> editorFactory = Wicketopia.get().createEditorFactory(Person.class);
Context context = new Context(Context.CREATE);
form.add(new CssBeanViewLayoutPanel<Person>("layout", beanType, model, context, editorFactory));
                

Here, we again ask Wicketopia to create an editor component factory, but rather than manually generating the components, we just instantiate a CssBeanViewLayoutPanel and let it use the factory to generate all the fields labels/components for the Person class. For each property, the CssBeanViewLayoutPanel will generate a section that looks like:

CSS Bean View Layout Markup

<div class="prop-div">
  <div class="prop-label"></div>
  <div class="prop-component"></div>
</div>

Sometimes, we don't want all of the properties to be displayed. We can control that by passing in a list of property names to the constructor of our layout panel:

Dynamically-Generated Form with Specified Properties...

Form<Person> form = new Form<Person>("form", model);
PropertyComponentFactory<Person> editorFactory = Wicketopia.get().createEditorFactory(beanType);
Context context = new Context(Context.CREATE);
form.add(new CssBeanViewLayoutPanel<Person>("layout", beanType, model, context, editorFactory, "firstName", "lastName"));

Here, we're using a layout panel as we were before, but we're telling it to only display the "firstName" and "lastName" properties.