Reputation: 411
Trying to learn how to create a dynamic html form. The elements would be defined in the database. Once page is created, the post back data will be handled by controller to insert the data into the database.
I am using playframework 1.2.4
would appreciate any guideline/ helpful links
I can build the page if i know what the elements are and can pull data out for select list from a database table when i call render(param object) from my controller and access the object in my view.
My hack so far: Created a table with following columns
rid
HTMLElementType
ElementName
HTMLElementOptions [if the element type is select]
HTMLDefaultValue [default value for select like 'select a value from below']
HTMLElementEnabled
Created a model
package models;
import play.*;
import play.db.jpa.*;
import play.data.validation.*;
import javax.persistence.*;
import java.util.*;
@javax.persistence.Entity
@Table(name="mytable")
public class DynameForm extends Model{
public String HTMLElementType;
public String ElementName;
public String HTMLElementOptions;
public String HTMLDefaultValue;
public String HTMLElementEnabled;
}
In my view i loop through checking if it a <select>
and if so put in an empty option. But not sure if that is right way to go about. In addition in my view i also have to check if it is not then i have to put in <input type=>
and build the complete tag
In addition how would I enforce validation on certain fields that are required like example last name/ ssn/ etc? I can alter my table to have a column IsRequired which could help me
Not sure what the right way even is to capture the data on post back
Upvotes: 4
Views: 1360
Reputation: 2984
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
}
Upvotes: 2