Play框架 - 为动态字段注册自定义DataBinder

时间:2015-02-16 04:56:41

标签: playframework playframework-2.3 dynamicform

使用Play 2.3.7(Java)我有以下场景。

我有一个班级CSVData,其中包含CSVField类型的列表。以下是这些类的属性:

public class CSVData{

private String name;
private String description;
private String dataFilePath;
private List<CSVField> fields;
private Double latitude;
private Double longitude;


// rest of class... }

public class CSVField {
    private String name;
    private String type;

...}

制作表单以输入CSVData时遇到的困难是我有这个嵌套的List<CSVField>属性,而CSVField是包含两个字符串的自定义类型。我需要表单是动态的,因为它应该能够接受任意数量的CSVField s(至少1)。根据{{​​3}},似乎我应该为CSVField注册自定义DataBinder,但是我找不到任何使用多个输入字符串执行此操作的示例。 Java Form Documentation类似,但它只绑定一个字段。

This example我希望拥有哪种类型的用户输入。我使用Here is a video制作了我的观点。文本字段(名称)和选择下拉项(类型)的组合是我需要绑定到CSVField然后添加到List<CSVField> fields对象中的CSVData的组合。 如何使用Play框架执行此操作?


编辑:在我的控制器中,我尝试了这个

Form<CSVData> formData = Form.form(CSVData.class).bindFromRequest();

在视图中我尝试了这个

@helper.repeat(csvForm("fields"), min = 1) { csvField =>

    @multiDataField(csvField,
        label = "Column Name and Type",
        gsnTypes,
        help = "Enter the column names and respective types for the data items in the file")

}

multiDataFieldthis example code for adding dynamic fields模板的位置。但它没有正确绑定动态字段,并在fields上抛出了无效的验证错误。我认为我的问题是我不知道在name模板中使用哪些multiDataField属性。有什么建议吗?

1 个答案:

答案 0 :(得分:3)

您不需要任何客户数据存储器。支持具有复杂对象的列表,无需任何其他绑定注册。

在视图中,您可以使用@repeat助手,在控制器中,您已经做得很好。

这里有一个关于Play and Forms的完整示例,或直接在TypeSafe

修改

在重复块中,csvField是List中每个Form对象的一个​​实例。然后,您需要添加视图所需的所有HTML元素。例如(没有Bootstrap简化):

@helper.repeat(csvForm("fields"), min = 1) { csvField =>
    Name: <input type="text" name='@csvField("name").name' value='@csvField("name").value'>
    Type: <input type="text" name='@csvField("type").name' value='@csvField("type").value'>
}

您可以使用samples provide in Play 2.2.x找到更完整的示例。要在2.3.x中编译它可能需要更改一些东西并且不使用Bootstrap 3.x,但逻辑是相同的。

编辑(2)

如果要将动态元素添加到视图中,则需要注意添加新元素时,设置正确的数组编号。为此你需要使用JQuery:

$('.addCSVField').click(function() {
    var CSVFields = $(this).parents('.CSVField');
    var template = $('.CSVField_template', CSVFields);
    template.before('<div class="clearfix CSVField">' + template.html() + '</div>');
    renumber();
})

$('.removeCSVField').click(function() {
    $(this).parents('.CSVField').remove();
    renumber(); 
})  

var renumber = function() {
    $('.CSVField').each(function(i) {
        $('input', this).each(function() {
            $(this).attr('name', $(this).attr('name').replace(/fields\[.+?\]/g, 'fields[' + i + ']'));
        })
    })
}

然后您需要将HTML / Scala代码更改为:

@fieldGroup(field: Field, className: String = "CSVField") = {
    <div class="well @className">
        <a class="removeCSVField btn danger pull-right">Remove this field</a>
        Name: <input type="text" name='@field("name").name' value='@field("name").value'>
        Type: <input type="text" name='@field("type").name' value='@field("type").value'>
    </div>
}   

@repeat(csvForm("fields")) { csvField =>
    @fieldGroup(csvField)
}

@**
 * Keep an hidden block that will be used as template for Javascript copy code
 **@
@fieldGroup(csvForm("fields[x]"),className = "CSVField_template")   
<a class="addCSVField btn success">Add another field</a>

添加CSS样式.CSVField_template{display: none;}

我没有测试任何一个,所以它可能无法编译。但是,我只是按照与Forms example (play 2.2.x

类似的方式进行了跟踪