问题
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).
回答1:
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.
来源:https://stackoverflow.com/questions/26604516/wicket-fileuploadfield-with-listview