问题
I'm trying to download a csv file after applying filters to the DataProvider.
For some reason the filtered results are shown in the Grid, but the downloaded csv file still contains all data.
@AutoView
class FinancialTransactionsView : VerticalLayout(), View {
private val grid: Grid<FinancialTransaction>
private val yearField: ComboBox<Int>
private val dataProvider = DataProvider.ofCollection(FinancialTransaction.findAll())
private val fileDownloader: FileDownloader
init {
label("Financial Transactions") {
styleName = ValoTheme.LABEL_H1
}
yearField = comboBox("Select Year") {
setItems(listOf(2016, 2017, 2018))
addSelectionListener {
// Filter the data based on the selected year
if (it.value != it.oldValue) setDataProvider()
}
}
// Create FileDownloader and initialize with all contents in the DataProvider
fileDownloader = FileDownloader(createCsvResource())
val downloadButton = button("Download csv") {
styleName = ValoTheme.BUTTON_PRIMARY
onLeftClick {
// The idea here is to assign values from the filtered DataProvider to the FileDownloader
fileDownloader.fileDownloadResource = createCsvResource()
}
}
fileDownloader.extend(downloadButton)
fileDownloader.fileDownloadResource = createCsvResource()
grid = grid(dataProvider = dataProvider) {
expandRatio = 1f
setSizeFull()
addColumnFor(FinancialTransaction::companyId)
addColumnFor(FinancialTransaction::fiscalYear)
addColumnFor(FinancialTransaction::fiscalPeriod)
addColumnFor(FinancialTransaction::currency)
addColumnFor(FinancialTransaction::finalizedDebitAmountInCurrency)
addColumnFor(FinancialTransaction::finalizedCreditAmountInCurrency)
appendHeaderRow().generateFilterComponents(this, FinancialTransaction::class)
}
}
private fun createCsvResource(): StreamResource {
return StreamResource(StreamResource.StreamSource {
val csv = dataProvider.items.toList().toCsv()
try {
return@StreamSource csv.byteInputStream()
} catch (e: IOException) {
e.printStackTrace()
return@StreamSource null
}
}, "financial_transactions.csv")
}
private fun setDataProvider() {
dataProvider.clearFilters()
if (!yearField.isEmpty)
dataProvider.setFilterByValue(FinancialTransaction::fiscalYear, yearField.value)
}
}
toCsv()
is an extension function List<FinancialTransaction>
which returns a string containing csv data.
What can I do to get the filtered results in my csv file?
回答1:
val csv = dataProvider.items.toList().toCsv()
I am not Kotlin guy, but I assume dataProvider.items is a shorthand to dataProvider.getItems() in Java, i.e. this method (and you use ListDataProvider)
https://vaadin.com/download/release/8.4/8.4.1/docs/api/com/vaadin/data/provider/ListDataProvider.html#getItems--
In Vaadin getItems() returns all items by passing all filters.
So instead you should do either of the following
dataProvider.fetch(..)
https://vaadin.com/download/release/8.4/8.4.1/docs/api/com/vaadin/data/provider/DataProvider.html#fetch-com.vaadin.data.provider.Query-
Where you give the filters you want to apply in the query, or
grid.getDataCommunicator.fetchItemsWithRange(..)
https://vaadin.com/download/release/8.4/8.4.1/docs/api/com/vaadin/data/provider/DataCommunicator.html#fetchItemsWithRange-int-int-
Which returns list of items with filters you have set applied, which I think is ideal for you
回答2:
Thank you for using Vaadin-on-Kotlin!
I've just updated the Databases Guide which should hopefully answer all of your questions. If not, just let me know and I'll update the guides accordingly.
The
ListDataProvider.items
will not apply any filters and will always return all items. You need to use thegetAll()
extension function in order to obey the filters set by the Grid. This is now explained in the Exporting data from DataProviders chapter of the Databases Guide.In your code, both the
grid
and theyearField
will set the filter to the same data provider, thus overwriting values set by each other. Please read the Chaining Data Providers chapter in the Databases Guide to learn how to AND multiple filters set by multiple components.When you use
private val dataProvider = DataProvider.ofCollection(FinancialTransaction.findAll())
, that will load all transactions from the database in-memory. You can use a more memory-efficient way:private val dataProvider = FinancialTransaction.dataProvider
(given thatFinancialTransaction
is anEntity
)
Please let me know if this answers your questions. Thanks!
来源:https://stackoverflow.com/questions/50318586/use-filtered-dataprovider-contents-when-filedownloader-is-called-in-vaadin