Wicket:具有ListView的FileUploadField [英] Wicket: FileUploadField with ListView
问题描述
-
我有一个用来上传多个文件的页面。对于每个文件,用户必须指定一个类型和描述,这就是为什么我不能使用
MultiFileUploadField
...所以我使用RepeatingView
,每个元素中包含一个FileUploadField
以及我需要的其他两个字段。
- 问题在于,无论何时单击添加文件按钮(
AjaxLink
),已经存在的 FileUploadFields
一个文件,被重置为空... 我能做什么?
以下是 ListView
(抱歉,它不是 RepeatingView
,而是一个 ListView
):
$ b
IModel< List< EtdDokument>> listModel = getListModel();
ListView< EtdDokument> dokumenteList = new ListView< EtdDokument>(dokumenteList,listModel){
private static final long serialVersionUID = 1L;
$ b $ @Override
protected void populateItem(ListItem< EtdDokument> item){
final boolean showHeaders =((getList()== null)|| getList() )== 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
来选择文档类型(我们自己的分类)。
好了,因为html的< input type =file>
在更新之后丢失了它的选择,而且真正的模型对象(选择了文件)仅当 post
事件发生时设置 FileUploadField
。因此,即使我们在 onchange
事件中添加了 AjaxEventBehavior
到我们的文件面板,它的模型在用户选择文件。
实际上,我们可以在 post
请求之前访问所选文件,只能从js请求, '脚本,将已经选定的文件保存在某个数组中,而ajax更新被处理,然后将其设置回来,但是令人生厌。
所以,另一种解决方法这个问题是只对新添加的组件进行更新,不要触及其他组件。
我将使用 RepeatingView
,因为我只需要点击 addLink
而不是根据模型生成新的wicket id。这里是代码(仔细阅读注释):
/ *方法, /
private void init()
{
/ *容器,其中包含所有FileUploadFields,
作为RepeatingView将子项添加到它的父对象。 * /
WebMarkupContainer container = new WebMarkupContainer(container);
/ *我们需要DOM id作为容器组件。 * /
container.setOutputMarkupId(true);
add(container);
final RepeatingView rv = new RepeatingView(dokumenteList);
container.add(rv);
$ b $ *我们需要通过ourselfs添加所有的默认模型值来重复查看:* /
(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);
...
/ *就是这样。我们动态地将创建的早期组件添加到标记。
这允许我们通过ajax更新这个组件。 * /
target.prependJavaScript(
var item = document.createElement('div');+ //创建空'div'标签
item.id ='+ r .getMarkupId()+';+ //设置这个'div'的标记ID
Wicket。$('+ container.getMarkupId()+').appendChild(item); /添加这个'div'作为容器子。
);
$ b $ *新增'div'仍然是空的,但是这个更新将会用真实的组件的标记来代替
。* /
target.add(r);
}
};
add(addLink);
}
/ *此方法创建EDRowP的新实例(带有随机ID),并将
添加到RepeatingView中。
我已经放弃了你的headRow的实现,但是你可以把它包含到EDRowPanel中,或者实现类似的功能。
* /
private EtdDokumentRowPanel createDocumentRow(RepeatingView rv,EtdDokument doc)
{
EtdDokumentRowPanel row = new EtdDokumentRowPanel(rv.newChildId(),doc);
rv.add(row);
返回行;
$ / code>
在标记中:
< form ...>
...
< div wicket:id =container>
< div wicket:id =dokumenteList>< / div>
< / div>
< a href wicket:id =addDokument>添加< / a>
....
< / form>
对于小问题,这看起来太麻烦了,但是我认为没有更优雅的解决方案(或者可能我现在太困了,去看看吧)。这应该工作。
I have a page that is used to upload several files. For each file, the user must specify a type and a description, that's why I can't use
MultiFileUploadField
... so I use aRepeatingView
with aFileUploadField
in each element along with the other two fields I need.The problem is that whenever the "add File" button is clicked (
AjaxLink
), theFileUploadFields
that already had a file, are reset to null...
What can I do?
Here is the ListView
(sorry, it wasn't a RepeatingView
but a 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);
- The
EtdDokumentRowPanel
has nothing interesting, I just show aFileUploadField
, aTextField
for the file description and aDropDownChoice
to select the type of document (our own classification).
Ok, it's a bit tricky, because html's <input type="file">
losts it's selection after any update, and real model object (choosen file) for FileUploadField
is set only when post
event occurs. So, even if we add AjaxEventBehavior
with onchange
event into our file panel - it's model will be null after user selects file.
Actually, we have access to the chosen file before post
request only from js and you can implement 'saving' script, to hold already selected files in some array, while ajax update is proccessed, and then set them back, but it is tediously.
So, another way to solve this issue is to proccess update only on newly added component and don't touch others.
I will use RepeatingView
, because I need to generate new wicket ids only when I click addLink
and not according to the model. Here's the code (read comments carefully):
/* 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;
}
And in markup:
<form...>
...
<div wicket:id="container">
<div wicket:id="dokumenteList"></div>
</div>
<a href wicket:id="addDokument">Add</a>
....
</form>
It looks like too cumbersome solution for small problem, but I think, that there is no more elegant one (or may be I am too sleepy now, to see it ). And this should work.
这篇关于Wicket:具有ListView的FileUploadField的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!