在Wicket中检索表单的动态添加输入的值

时间:2014-05-15 11:05:19

标签: java wicket

我正在构建一个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>,其中键是名称和输入值的值。

3 个答案:

答案 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();
  }
});