FileDownloader 和复选框,下载选中的项目

FileDownloader and checkbox, download selected items

我们创建了解决方案,其中用户有一个 table 文件,每个条目都有复选框。他可以 select 任意数量,然后单击下载按钮。

我们正在使用这样的资源,它应该允许动态下载,具体取决于 selected 项目

private StreamResource createResource(final IndexedContainer container) {
        return new StreamResource(new StreamSource() {
            @Override
            public InputStream getStream() {

                for (Object o : container.getItemIds()) {
                    CheckBox checkbox = (CheckBox) container.getItem(o).getItemProperty(C_CHECK_BOX).getValue();
                    if (checkbox.getValue()) {
                        selectedFiles.add(o);
                    }
                }
                // do some magic to get stream of selected files


            }
        }, "download.zip");
}

问题是只有第二次和随后的按钮点击给出了预期的结果。

事实证明,FileDownoader 正在从服务器获取资源,然后发送组件的当前状态。这就是第一次点击给出陈旧结果的原因。

你知道如何克服这个问题吗?是否可以强制:先更新组件再下载资源?

非常感谢 帕维尔

FileDownloader 不适合您的需要。正如您在文档中看到的那样:

Download should be started directly when the user clicks e.g. a Button without going through a server-side click listener to avoid triggering security warnings in some browsers.

这意味着您无法动态生成由复选框值决定的 download.zip 文件,因为这需要访问服务器。

您至少有 2 个选项。每次用户对复选框进行更改时,要么创建新的 FileDownloader 并生成新的 Resource download.zip。或者您可以使用这行代码向您的 Button 添加简单的 ClickListener

getUI().getPage().open(resource, "_blank", false);

相关:Vaadin - How to open BrowserWindowOpener from a SINGLE BUTTON

默认情况下,Vaadin 中的 CheckBox 是非立即的,这意味着当复选框在浏览器上被选中(或取消选中)时,它不会向服务器发送请求。即时组件也将排队的非即时事件发送到服务器,但 FileDownloader 似乎不会导致将非即时复选框值发送到服务器的事件。

您唯一需要做的就是在创建这些复选框时将其设置为立即显示:

checkBox.setImmediate(true);

还有另一种解决方案来设置 checkBox.setImmediate(true); 。可以在单击之前发送所有组件的当前状态,而不是发送每个复选框更改。

此解决方案基于此答案:

您需要创建文件下载器按钮并将其隐藏:

Button hiddenButton = new Button();    
hiddenButton.setId(HIDDEN_ID);
hiddenButton.addStyleName("InvisibleButton");
StreamResource zipResource = createResource(container);
FileDownloader fd = new FileDownloader(zipResource);
fd.extend(hiddenButton);

将 css 规则添加到您的主题

.InvisibleButton {
    display: none;
}

然后创建另一个按钮,第一次更新状态,然后点击隐藏按钮。

Button zipDownload = new Button("Download as ZIP file");
zipDownload.addClickListener(new Button.ClickListener() {
     @Override
     public void buttonClick(Button.ClickEvent event) {    
          Page.getCurrent().getJavaScript()
         .execute(String.format("document.getElementById('%s').click();", HIDDEN_ID));
            }
        });