Wicket:具有ListView的FileUploadField [英] Wicket: FileUploadField with ListView

查看:119
本文介绍了Wicket:具有ListView的FileUploadField的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


  • 我有一个用来上传多个文件的页面。对于每个文件,用户必须指定一个类型和描述,这就是为什么我不能使用 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 a RepeatingView with a FileUploadField in each element along with the other two fields I need.

  • The problem is that whenever the "add File" button is clicked (AjaxLink), the FileUploadFields 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 a FileUploadField, a TextField for the file description and a DropDownChoice 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆