basically the problem is to generate an html form. You appear to have figured out your model. What you are missing is a view. I did something like the following once, to generate a model for a simpleDB model.
I provide a list of fields, and UI is generated based on the fields. I only had text fields, and only wanted 2 cases (visible and invisible) fields. Your usecase may require more complexity, so you can adapt as necessary.
dish.fields
contains the fields with the relevant metadata. Any special things like, requires validation, or isRequired, you will have to provide that information to the view, so it can render the field in appropriate manner.
Simplest way to model it would be to begin with an HTML form, and start generalizing it one field at a time.
#{list items:dish.fields, as:'f'}
#{field 'f'}
#{if f.display }
<div class="control-group">
<label class="control-label"> &{f.name} </label>
<div class="controls">
<input type="text" class="input-xlarge" placeholder="&{f.name}" name="${dish.getFieldId(f)}" value="${dish.getValue(f)}" ></input>
</div>
</div>
#{/if}
#{else}
<input type="hidden" class="input-xlarge" placeholder="&{f.name}" name="${dish.getFieldId(f)}" value="${dish.getValue(f)}" ></input>
#{/else}
#{/field}
#{/list}
#{else}
No fields
#{/else}
I had to define my own fields, but you should be able to get the idea.
You will probably have to have a bunch of different input types for different use cases, so start with simple and generalize as you go on. You can have a look at the CRUD module implementation as well.
my DisplayAttribute
class (metadata for the fields) looks something like the following. You can use it as a starting point.
public class DisplayAttribute {
public Boolean display = Boolean.TRUE;
public String type = "";
public String name;
public DisplayAttribute(String name){
this.name = name;
this.display = Boolean.TRUE;
}
public DisplayAttribute(String name, Boolean display){
this.name = name;
this.display = display;
}
... overridden equals and hash
}
edit
How do the fields get rendered?
Controller passes the meta data(DisplayAttribute
) to the view, in this case, meta data only contains name of the field and wether it is displayable or not.
Model
Here model contains the fields to render, but you could just as easily retrieve these from a database. My model is generic because I realized I kept on doing the same things over and over again for multiple models.
I implement my own interface which gives me getFields
method. I also maintain two maps, so that given an attribute, I can get its DisplayAttribute, and given a DisplayAttribute I get its name. I call methods of this model from the view when needed.
public class GenericSimpleDBModel implements SimpleDBModel {
public static AmazonSimpleDB sdb = null;
private static final String bracketRemovalPattern = "(^.*?\\[|\\]\\s*$)";
private Map<DisplayAttribute, Set<String>> data = new TreeMap<DisplayAttribute, Set<String>>(new UuidComparator());
private Map<String, DisplayAttribute> attributeCache = new HashMap<String, DisplayAttribute>();
protected final String DOMAIN_NAME;
public GenericSimpleDBModel() {
initialize(getFields());
this.DOMAIN_NAME = "dishes";
}
protected void initialize(String[] fields) {
data = new TreeMap<DisplayAttribute, Set<String>>(new UuidComparator());
attributeCache = new HashMap<String, DisplayAttribute>();
for (String f : fields) {
// if (f.equals(getUUIDField()) || f.equals(getIntegrityField())) {
if (f.endsWith("uuid") || f.endsWith("integrity")) {
setValue(f, "", Boolean.FALSE);
} else {
setValue(f, "", Boolean.TRUE);
}
}
}
protected void initialize(Set<DisplayAttribute> fields) {
data = new TreeMap<DisplayAttribute, Set<String>>(new UuidComparator());
attributeCache = new HashMap<String, DisplayAttribute>();
for (DisplayAttribute atr : fields) {
setValue(atr.name, "");
}
}
... more methods
}