4

尝试学习如何创建动态 html 表单。元素将在数据库中定义。创建页面后,控制器将处理回发数据以将数据插入数据库。

我正在使用 playframework 1.2.4

将不胜感激任何指南/有用的链接

如果我知道元素是什么,我可以构建页面,并且当我从控制器调用 render(param object) 并访问视图中的对象时,可以从数据库表中提取数据以用于选择列表。

到目前为止我的 hack:创建了一个包含以下列的表

rid
HTMLElementType
ElementName
HTMLElementOptions [if the element type is select]
HTMLDefaultValue [default value for select like 'select a value from below']
HTMLElementEnabled

创建了一个模型

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

4

1 回答 1

2

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
}
于 2012-10-30T20:31:00.130 回答