我有一个用于上传多个文件的页面。对于每个文件,用户必须指定类型和描述,这就是我无法使用MultiFileUploadField
的原因...所以我在每个元素中使用RepeatingView
和FileUploadField
以及我需要的其他两个领域。
问题在于,只要点击“添加文件”按钮(AjaxLink
),已经有文件的FileUploadFields
就会重置为空...
我该怎么办?
以下是ListView
(抱歉,它不是RepeatingView
而是ListView
):
IModel<List<EtdDokument>> listModel = getListModel();
ListView<EtdDokument> dokumenteList = new ListView<EtdDokument>("dokumenteList", listModel) {
private static final long serialVersionUID = 1L;
@Override
protected void populateItem(ListItem<EtdDokument> item) {
final boolean showHeaders = ((getList() == null) || getList().size() == 0);
final WebMarkupContainer headRow = new WebMarkupContainer("headRow");
headRow.setVisible(showHeaders);
item.add(headRow);
EtdDokumentRowPanel etdDokumentRow = new EtdDokumentRowPanel("bodyRow", item.getModel());
item.add(etdDokumentRow);
}
};
dokumenteList.setReuseItems(true);
add(dokumenteList);
AjaxLink<Void> addLink = new AjaxLink<Void>("addDokument") {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
EtdConfiguration etdConfig = EtdConfigForm.this.getModelObject();
final EtdDokument newValue = new EtdDokument(etdConfig);
tempEtdDokumente.add(newValue);
target.addComponent(EtdConfigForm.this);
}
};
add(addLink);
EtdDokumentRowPanel
没有什么有趣的,我只显示FileUploadField
,TextField
表示文件说明,DropDownChoice
表示选择文档类型(我们自己的分类) )。答案 0 :(得分:2)
好吧,这有点棘手,因为html&#39; <input type="file">
在任何更新后失去了它的选择,FileUploadField
的真实模型对象(选择文件)是仅在post
事件发生时设置。因此,即使我们将AjaxEventBehavior
onchange
事件添加到我们的文件面板中,用户选择文件后它的模型也会为空。
实际上,我们只能在post
请求来自js之前访问所选文件,您可以实施“保存”#39;脚本,在某些数组中保存已选择的文件,同时执行ajax更新,然后将它们设置回来,但这很繁琐。
因此,解决此问题的另一种方法是仅对新添加的组件进行更新,而不要触及其他组件。
我将使用RepeatingView
,因为只有在我点击addLink
而不是根据模型时才需要生成新的wicket ID。这是代码(仔细阅读评论):
/* Method, which init your form */
private void init()
{
/* Container, which will hold all FileUploadFields,
as RepeatingView adds children to it's parent object. */
WebMarkupContainer container = new WebMarkupContainer("container");
/* We need DOM id for container component. */
container.setOutputMarkupId(true);
add(container);
final RepeatingView rv = new RepeatingView("dokumenteList");
container.add (rv);
/* We need to add all default model values by ourselfs for RepeatingView: */
for(EtdDokument doc : getListModel().getObject())
{
createDocumentRow(rv, doc);
}
final AjaxLink<String> addLink = new AjaxLink<String>("addDokument") {
@Override
public void onClick(AjaxRequestTarget target) {
final EtdDokument newValue...;
final EtdDokumentRowPanel r = createDocumentRow(rv, newValue);
...
/* This is it. We dynamicly adding created earlier component to markup.
This allows us to update this component via ajax. */
target.prependJavaScript(
"var item=document.createElement('div');" + //creating empty 'div' tag
"item.id='" + r.getMarkupId() + "'; " + // set markup id for this 'div'.
"Wicket.$('" + container.getMarkupId() + "').appendChild(item);" // add this 'div' as container child.
);
/* Added 'div' is still empty, but this update will replace
it, by real component's markup.*/
target.add(r);
}
};
add(addLink);
}
/* This method creates new instance of EDRowP (with random id) and adds
it to RepeatingView.
I have dropped the implementation of your headRow, but you can include it
into the EDRowPanel or implement something similar.
*/
private EtdDokumentRowPanel createDocumentRow( RepeatingView rv, EtdDokument doc )
{
EtdDokumentRowPanel row = new EtdDokumentRowPanel(rv.newChildId(), doc);
rv.add(row);
return row;
}
在标记中:
<form...>
...
<div wicket:id="container">
<div wicket:id="dokumenteList"></div>
</div>
<a href wicket:id="addDokument">Add</a>
....
</form>
对于小问题来说,这看起来太麻烦了,但我认为,没有更优雅的解决方案(或者现在可能我太困了,看看它)。这应该有用。