我们已经创建了一个解决方案,其中用户有一个包含文件的表,每个条目都有一个复选框。他可以根据需要选择多个,然后单击下载按钮。
我们正在使用这样的资源,它应该允许动态下载,具体取决于所选项目
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正在从服务器获取资源,然后它正在发送组件的当前状态。这就是为什么第一次点击会产生陈旧结果的原因。
你知道如何克服这个问题吗?是否可以强制:首先更新组件然后下载资源?
非常感谢 的Pawel
答案 0 :(得分:2)
默认情况下,Vaadin中的CheckBox是非立即的,这意味着当浏览器上选中(或取消选中)复选框时,它不会向服务器发送请求。立即组件也将排队的非立即事件发送到服务器,但似乎FileDownloader不会导致将非立即复选框值发送到服务器的事件。
您唯一需要做的就是在创建时立即将复选框设置为:
checkBox.setImmediate(true);
答案 1 :(得分:0)
FileDownloader不适合您的需求。正如您可以在文档中看到的那样:
下载应该在用户点击时直接启动,例如一个Button,无需通过服务器端点击监听器,以避免在某些浏览器中触发安全警告。
这意味着您无法动态生成由复选框值确定的download.zip
文件,因为这需要访问服务器。
您至少有2个选项。每次用户更改复选框时,都可以创建新的FileDownloader
并生成新的Resource
download.zip
。或者您可以使用以下代码行向您添加简单的ClickListener
:
getUI().getPage().open(resource, "_blank", false);
相关:Vaadin - How to open BrowserWindowOpener from a SINGLE BUTTON
答案 2 :(得分:0)
还有另一种设置checkBox.setImmediate(true);
的解决方案。可以在单击之前发送所有组件的当前状态,而不是发送每个复选框更改。
此解决方案基于以下答案:https://stackoverflow.com/a/30643199/1344546
您需要创建文件下载按钮并隐藏它:
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));
}
});