Wicket CheapoModel

Sometimes you just want a very simple Model in Wicket, where you can put stuff in and get it out later via a simple property expression or a method call. For a sign-in form, for instance, you’d have two text fields for user name and password, and in onSubmit() you’d get their values and authenticate with them.

In Jonathan Locke‘s simple sign-in example of the Wicket 1.3 examples, he creates a ValueMap and uses that in a PropertyModel with the simple “username” and “password” expressions:

// El-cheapo model for form
private final ValueMap properties = new ValueMap();

// Let Components set values via a PropertyModel.
add(new TextField("username", new PropertyModel(properties, "username")));

// Get those values, e.g. in onSubmit().
session.authenticate(properties.getString("username"));

That works fine and is simple enough. It does require a bit of boilerplate code, though, and repetition of the property expression Strings in the code. Factoring them out into constants would work, but still be ugly.

The simple CheapoModel class below hides these internals and makes the code shorter and easier to read. It also provides a getter for the property expression itself, as it’s convenient and improves readability to use it as component id: one literal less. Use CheapoModel like this:

private final CheapoModel uri = new CheapoModel("uri");

// Use its PropertyModel and the property expression when building components.
add(new TextField(uri.id(), uri.model());

// Retrieve the value after the user has interacted with the component.
final String newUri = uri.value();

You can also pass in the ValueMap if you want to share one.

Here it is:

package foo.example;

import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.util.value.ValueMap;

/**
 * Instantiate with an expression, and get a PropertyModel with getters
 * for the value and the expression itself, so you don't have to repeat
 * the expression in your code:
 * 
 * private final CheapoModel uri = new CheapoModel("uri");
 * 
 * // use with its PropertyModel in Components
 * add(new TextField(uri.id(), uri.model());
 * 
 * // query, e.g. in onSubmit()
 * final String newUri = uri.get();
 * 
 * 
 * Pass the ValueMap in yourself using the other constructor if you have
 * multiple expressions and want to avoid creating a new ValueMap for
 * each one.
 * 
 * @author Thomas Kappler 
 */
public class CheapoModel
{
    final ValueMap map;
    final String expr;
    
    
    public CheapoModel(final String expr)
    {
        this(expr, new ValueMap());
    }
    
    public CheapoModel(final String expr, ValueMap map)
    {
        this.map = map;
        this.expr = expr;
    }
    
    
    public PropertyModel model()
    {
        return new PropertyModel(map, expr);
    }
    
    public String value()
    {
        return map.getString(expr);
    }
    
    public String id()
    {
        return expr;
    }
}
package foo.example;

import org.apache.wicket.util.value.ValueMap;

import junit.framework.TestCase;


public class CheapoModelTest extends TestCase
{
    public void testBasics()
    {
        final CheapoModel c = new CheapoModel("foo");
        
        assertEquals("foo", c.id());
        
        assertNotNull(c.model());
        assertEquals("foo", c.model().getPropertyExpression());
    }
    
    public void testWriteThrough()
    {
        final ValueMap map = new ValueMap();
        final CheapoModel c = new CheapoModel("foo", map);

        assertNull(c.value());
        map.add("foo", "value");
        assertNotNull(c.value());
        assertEquals("value", c.value());
    }
}

Edited 2009-08-06: fixed code duplication in the constructors, small clarifications to post.

Advertisements

Tags: , , , ,


%d bloggers like this: