我正在构建一个Wicket WebPage
,它可以动态构建具有多种不同输入类型的表单。可以添加文本文件,复选框和下拉列表。对于每种类型,通过ListView
和不同Panel
添加不同的输入。表单的创建有效,但现在我不知道如何在onSubmit()
方法中访问输入的值。
这是我页面的构造函数:
public AddJobPage(final PageParameters params) {
super(params);
final Workable w = WorkableManager.getInstance().findWorkableByName(params.get("workableName").toString());
final List<FormElement> formElements = w.getParameterFormDescriptor();
final ListView<FormElement> listView = new ListView<FormElement>("inputs", formElements) {
@Override
protected void populateItem(final ListItem<FormElement> item) {
switch (item.getModelObject().getType()) {
case TEXT:
item.add(new TextFieldPanel("formElement", item.getModel()));
break;
case DROPDOWN:
item.add(new DropDownPanel("formElement", item.getModel()));
break;
case CHECKBOX:
item.add(new CheckBoxPanel("formElement", item.getModel()));
break;
default:
break;
}
}
};
listView.setReuseItems(true);
final Form<Void> parameterForm = new Form<Void>("parameterForm") {
@Override
protected final void onSubmit() {
// What comes here?
}
};
parameterForm.add(listView);
add(parameterForm);
}
TextFieldPanel
定义如下:
public class TextFieldPanel extends Panel {
public TextFieldPanel(final String id, final IModel<FormElement> model) {
super(id, model);
final FormElement el = model.getObject();
final Label label = new Label("label", el.getLabel());
final TextField<String> textfield = new TextField<>("textfield", Model.of(""));
label.add(new AttributeModifier("for", el.getParamName()));
textfield.add(new AttributeModifier("name", el.getParamName()));
textfield.add(new AttributeModifier("id", el.getParamName()));
add(label);
add(textfield);
}
}
FormElement
只描述了应该创建什么类型的输入。那么如何将提交的值与其名称(来自HTML属性)一起获取?
最后我想得到一个Map<String, String>
,其中键是名称和输入值的值。
答案 0 :(得分:4)
我相信您没有正确使用该表单。
您缺少的要点是您应该尽可能多地使用模型。这是因为组件几乎总是希望与某种数据一起使用,而且数据通常来自模型。例如,TextField
的模型将是文本字段存储其输入的位置。对于Label
,它将从中获取其显示值。
你在做什么,是这样的:你忽略了TextField的功能,它自动处理输入并尝试自己动手。它的功能重复,并不好。
你应该在那里做什么,而是使用模型。首先,您应该在表单组件上使用模型,然后在onSubmit中,您可以获取这些组件的模型以获取其输入。
但是,如果您使用多个表单组件,则该方法不可行,因为您必须为onSubmit()
中的每个表单组件检索模型的值。
这是我们提出建议解决方案的地方。
主要思想:在表单上使用模型,并将该模型传递给所有表单组件。然后,当提交表单时,wicket会自动处理来自这些表单组件的输入并更新模型。由于该模型是表单的模型,因此在onSubmit
中您只需一次方法调用即可访问所有数据:
Object data = this.getModelObject();
当然,价值不一定是Object
,但我以它为例。
但是,您的方案中也存在一个难点;这是表单组件的动态数量。实际上并不难实现,但如果您想确定价值的来源,则取决于您的要求。我认为你不会,因为我认为它只是一些需求收集并继续这个假设。
您可以通过以下两种方式处理此问题:使用ValueMap
模型,或使用带有集合的自定义模型对象,这些集合的大小可变。我不太喜欢ValueMap
,所以我会跳过对此的解释,但是一旦你理解了模型如何处理表单,你就应该能够解决它。
所以第二种方式。第一步是为表单创建一个模型对象。我将假设您只有一种类型的动态输入,因为它与添加其他输入的过程相同。因此,让我们在您的页面上说,您将拥有可变数量的TextField
输入元素。
public class FormModel {
private List<String> textFieldData = new ArrayList<>();
public void setTextFieldData(List<String> textFieldData){
this.textFieldData = textFieldData;
}
public List<String> getTextFieldData(){
return textFieldData;
}
}
然后,当您创建表单时,请将此模型指定为表单的模型:
final Form<FormModel> parameterForm = new Form<FormModel>("parameterForm", Model.of(new FormModel());
现在是更复杂的部分。您使用的每个TextField
都必须写入该集合并从中接收数据。我这样做的方法是分配一个唯一的整数ID,它将作为集合的索引,以确保它们中的每一个都不会覆盖其他输入。接下来,我们使用wicket的功能,我们为每个文本字段创建PropertyModel
,这将指向该集合中的元素,如下所示:
final TextField<String> textfield = new TextField<>("textfield", new PropertyModel(formModel, "textFieldData." + id));
其中ID是分配给此文本字段的唯一ID,也是该集合的索引。
以这种方式创建所有文本字段后,当成功验证表单并调用onSubmit
时,表单模型将自动更新文本字段的输入。在这种情况下,您只需在表单中使用getModelObject()
来检索FormModel
类的对象,其中包含所有值。
我知道这很重要,我可能在你想要实现的目标上错了。但我相信,如果你计划继续使用检票口,那么学习模型如何工作将是最好的选择。模型是Wicket不可或缺的一部分,一旦你学会使用它们它们就很棒。我建议你阅读this piece about how models work,希望你能够围绕我试图解释的内容。祝你好运!
编辑:还有一件事;在您的代码中,您指定AttributeModifier
,在TextField
上设置ID属性。这通常是不可取的;您应该使用getMarkupID()
并在其他组件中使用默认标记ID,而不是将自己的标记ID分配给文本字段。
答案 1 :(得分:0)
您的TextFieldPanel应包含一个Model或对象,以将其输出写入:
public TextFieldPanel(final String id, final IModel<FormElement> model, IModel<String> content) {
...
final TextField<String> textfield = new TextField<String>("textfield", content);
...
}
现在您可以将一个Model添加到TextField以将内容写入。
答案 2 :(得分:0)
您可以迭代表单,获取id和值,并将它们设置在键值映射中。
form.visitFormComponents(new IVisitor<Component, Void>()
{
public void component(final Component component, final IVisit<Void> iVisit)
{
component.getMarkupId();
component.getDefaultModelObjectAsString();
}
});