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

Play Framework - Register a custom DataBinder for dynamic fields

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

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

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 是包含两个字符串的自定义类型。我需要表单是动态的,因为它应该能够接受任意数量的 CSVFields(至少 1)。跟Java Form Documentation, it seems like I should register a custom DataBinder for CSVField, however I can't find any examples that do this with multiple input strings. This example类似,不过它只绑定一个字段。

Here is a video of what type of user input I would like to have. I made my view using this example code for adding dynamic fields。文本字段(名称)和 select 下拉项(类型)的组合是我需要绑定到 CSVField 然后添加到 CSVData 中的 List<CSVField> fields目的。 如何使用 Play Framework 执行此操作?


编辑:在我的控制器中我试过这个

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 模板。但它没有正确绑定动态字段并在 fields 上抛出无效验证错误。我想我的问题是我不知道在我的 multiDataField 模板中使用什么 name 属性。有什么建议吗?

您不需要任何客户数据绑定器。无需任何额外的绑定注册即可支持包含复杂对象的列表。

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

这里有一个关于 Play and Forms, or directly in TypeSafe

的完整示例

编辑

在重复块内,csvField 是列表中每个 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

中类似的方法