Play Framework - 为动态字段注册自定义 DataBinder [英] Play Framework - Register a custom DataBinder for dynamic fields

查看:17
本文介绍了Play Framework - 为动态字段注册自定义 DataBinder的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我有一个 CSVData 类,它包含一个 CSVField 类型的列表.以下是这些类的属性:

公共类CSVData{私人字符串名称;私人字符串描述;私有字符串数据文件路径;私人列表领域;私人双纬度;私人双经度;//剩下的课... }

公共类 CSVField {私人字符串名称;私有字符串类型;...}

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

这里有一个视频说明我想要什么样的用户输入.我使用这个用于添加动态字段的示例代码来表达我的观点.文本字段(名称)和选择下拉项(类型)的组合是我需要绑定到 CSVField 然后添加到 List 的组合.CSVData 对象中的字段.如何使用 Play 框架执行此操作?

<小时>

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

FormformData = Form.form(CSVData.class).bindFromRequest();

在视图中我试试这个

@helper.repeat(csvForm("fields"), min = 1) { csvField =>@multiDataField(csvField,label = "列名和类型",gsn 类型,help = "为文件中的数据项输入列名和各自的类型")}

其中 multiDataField这个模板.但它没有正确绑定动态字段并在 fields 上引发无效的验证错误.我想我的问题是我不知道在我的 multiDataField 模板中使用什么 name 属性.有什么建议吗?

解决方案

您不需要任何客户数据绑定器.支持具有复杂对象的列表,无需任何额外的绑定注册.

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

这里有一个关于游戏和表单的完整示例,或直接在 TypeSafe

编辑

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

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

您可以在 示例中找到更完整的示例玩 2.2.x.要在 2.3.x 中编译它,可能需要稍作更改,并且不使用 Bootstrap 3.x,但逻辑是相同的.

编辑 (2)

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

$('.addCSVField').click(function() {var CSVFields = $(this).parents('.CSVField');var 模板 = $('.CSVField_template', CSVFields);template.before('<div class="clearfix CSVField">' + template.html() + '</div>');重新编号();})$('.removeCSVField').click(function() {$(this).parents('.CSVField').remove();重新编号();})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="好吧@className"><a class="removeCSVField btn risk pull-right">删除这个字段</a>名称:<input type="text" name='@field("name").name' value='@field("name").value'>类型:<input type="text" name='@field("type").name' value='@field("type").value'>

}@repeat(csvForm("fields")) { csvField =>@fieldGroup(csvField)}@*** 保留一个隐藏块,用作 Javascript 复制代码的模板**@@fieldGroup(csvForm("fields[x]"),className = "CSVField_template")<a class="addCSVField btn success">添加另一个字段</a>

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

我没有测试任何一个,所以它可能无法编译.但是,我只是遵循了与 表单示例(播放 2.2.x

Using Play 2.3.7 (Java) I have the following scenario.

I have a class CSVData which contains a list of type CSVField. Here are the attributes for these 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... }

and

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

...}

The difficulty when making a form to input CSVData is that I have this nested List<CSVField> attribute and CSVField is a custom type containing two strings. I need the form to be dynamic in that it should be able to accept an arbitrary amount of CSVFields (at least 1). According to the 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 is similar, but it only binds one field.

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. The combination of the text field (name) and select dropdown item (type) is what I need to bind to a CSVField and then add to the List<CSVField> fields in the CSVData object. How can I do this using the Play Framework?


EDIT: In my controller I have tried this

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

And in the view I try this

@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")

}

Where multiDataField is this template. But it doesn't bind the dynamic fields properly and throws an invalid validation error on fields. I think my problem is I don't know what name attributes to use in my multiDataField template. Any advice?

解决方案

You don't need any customer databinder. Lists with complex objects are supported without any additional binding registration.

In the view you can use the @repeat Helper and in the controller you are already doing it well.

Here you have a complete example about Play and Forms, or directly in TypeSafe

EDIT

Inside the repeat block, csvField is an instance of every Form object in your List. Then you will need to add all the HTML elements you need for your view. For example (simplified without 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'>
}

You can find a more complete example with the samples provide in Play 2.2.x. To compile it in 2.3.x maybe something need to be changed a bit and is not using Bootstrap 3.x, but the logic is the same.

EDIT (2)

If you want to add dynamically elements to the view, you will need to take care that when a new element is added, the right array number is set. For that you will need to use 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 + ']'));
        })
    })
}

And then you will need to change your HTML/Scala code to something like that:

@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>

And to add a CSS style .CSVField_template{display: none;}

I did not test any of that, so it may not compile. However, I just followed a similar apporach as in the Forms example (play 2.2.x

这篇关于Play Framework - 为动态字段注册自定义 DataBinder的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆