-
Notifications
You must be signed in to change notification settings - Fork 181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
save and reset filters / sorting #76
Comments
I just exposed the state information of the table to DTApp = function(data, ..., options = list()) {
library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
fluidRow(
verbatimTextOutput('foo'),
DT::dataTableOutput('tbl')
)
),
server = function(input, output, session) {
options$ajax = list(url = dataTableAjax(session, data))
# create a widget using an Ajax URL created above
widget = datatable(data, server = TRUE, ..., options = options)
output$tbl = DT::renderDataTable(widget)
output$foo = renderPrint(str(input$tbl_state))
}
)
}
DTApp(iris, options = list(stateSave = TRUE)) |
This is great @yihui! A few questions/comments:
|
|
|
Yes, you can specify the initial search string and ordering info for a table, e.g. library(DT)
datatable(mtcars, options = list(
search = list(search = 'Ma'), order = list(list(2, 'asc'), list(1, 'desc'))
)) These info can be obtained from the list |
Yes! That helps a lot. Thanks @yihui Somewhat related question: Could the DT inputs you created for factors be made accessible as shiny inputs? |
Hi there, Let's say you have a reactive event that fetches a dataset from a database, a datatable that displays it, and a button that updates that database when you select a row and click on it. For a workflow type of situation, one would want to implement When I initialize my table, I have options like I grab from the DB with a reactive event (here a reactive copy of the updated myIris dataset), then fetch it to the DT, with When you select a row and click the 'click me' button, it changes the species of the row, and forces the reactive to re-fetch the data, using the counter. If you change the length and do that several time, you'll notice the pageLength switching to 10, 25 and 50 in a weird, unexplainable behavior. This behavior happened to me also for other values of the
I looked at @vnijs app Radiant to see if he was doing things differently, and I saw that piece of JavaScript in the callback I thought of using a proxy and Thank you! |
@The-Dub The callback you noticed is just so I can clear the state of the table when needed. Radiant has a 'refresh' button that resets the app to its original state and I wanted that to work on the DT tables in the app as well. Don't have an answer to your actually question unfortunately. For my purposes, saving and restoring state works nicely with DT in version 0.2 (thanks again @yihui!) |
I couldn't understand why one of my coworker couldn't reproduce the problem I was experiencing. I did some (intense) digging and pulled half of my hair trying to figure out why that bug was only happening with me. I realized that the issue doesn't appear on a fresh session, but if you kill the app and relaunch it right away, then things will get screwy. I modified my code in my previous post to add starting page, to better illustrate the example. On a fresh session, turn the trace on with You can play with it, let's say change the length to 25 and go to page 2. If I then change row 80 by using the "Click Me" button, it works fine. row 80 has been changed to 'setosa', and the table was redrawn with the correct arguments, as the trace shows correctly ( Then if we kill the app in Shiny and relaunch it right away, the options have been correctly reinitalized. Now if I leave pageLength = 10, but go to page 3, choose row 80 and use the "click me" button, then things get weird. The trace shows that Shiny is sending the correct information to datatable If you exit the app, and come back, things are getting even more screwy each update. My take on this issue is that there is probably some kind of hidden object behind the scene that save the state, and one is recreated each time the app is launched, but they accumulate. Then datatable doesn't know which one to choose from and starts behaving like a madman. I tried to look into the code to find where this issue could be coming from, but no luck... Thanks @yihui for looking into this! |
Here is a version that uses myIris <- iris
myIris$Species <- as.character(myIris$Species)
library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
selectInput("fooselect", "Change to", choices = c(unique(as.character(iris$Species)))),
actionButton("foobar", "Click Me"),
DT::dataTableOutput('tbl')
),
server = function(input, output, session) {
myData <- function() {
# fetch the database
myIris[myIris$Species != input$fooselect, ]
}
output$tbl <- DT::renderDataTable(
myIris,
selection = 'single',
options = list(
lengthMenu = list(c(10, 25, 50, -1), c('10','25','50','All'))
)
)
proxy <- dataTableProxy('tbl', deferUntilFlush = FALSE)
observe({
replaceData(proxy, myData(), resetPaging = FALSE)
})
observeEvent(input$foobar, {
req(input$tbl_rows_selected)
# update database
rowNum <- rownames(myData()[input$tbl_rows_selected, ])
myIris[rowNum, 'Species'] <<- input$fooselect
replaceData(proxy, myData(), resetPaging = FALSE)
})
}
) |
Thanks Yihui, that's great! I knew I wasn't doing things the right way ahah Sorry for the late response, I encountered some issues trying to implement it. I switched to your way, and I'm having an issue when (In your previous code, changing the output$tbl to the following will throw the error:)
I think I understand what's going on, since all the data is on the client-side, and that Another question: what is the main difference between reloadData and replaceData? From looking at the function, it looks like replaceData is pretty much just calling dataTableAjax and then reloadData, but I'm can't really understand why So the saveState option should be used when the app is reload rather than in the app? Out of curiosity, do you know what was causing the issue with saveState? Thank you for your help! |
The help page
In my opinion, The requirement for the table to be client-side makes it tricky to modify the data when the |
Yes, I saw that for reloadData, I was just wondering when I should be using replaceData and when I should be using reloadData. Thanks for the behind the scenes explanation, it gives me a better understanding of how things work. EDIT: O.M.G. I finally figured out why things were breaking... Anyway, I just wanted to share a 'dirty' trick to download all the data using the Buttons extension and server-side processing. I pretty much create a proxy button in the dataTable, and when the button is clicked, it simulates a click on the actual shiny download link, using JS. Then, using CSS, I hide the actual download link from the user.
(I tried to implement the download link directly inside the Button extension (e.g. |
I thought for quite a while about the download button before when this issue was filed #267, but I didn't come up with an elegant solution. Your trick is very interesting. Thanks for sharing! |
No problem, glad I can give back to the community! I don't know enough about how shiny binds its input to R, but if there a way to "force bind" the download button to the output using its ID and class, after the DT table is generated, the download button could be directly implemented in the DT output, without a proxy and a hidden download link. That would probably be a question more for Joe Cheng. |
I'm trying to figure out if it is possible to save (and reset) settings provided to DT by a user (this is related to #66).
In my shiny app I use some functions called on session$onSessionEnded to maintain state if a user hits refresh and, more importantly, to restore state from a file. To do something similar with input to DT it seems I would need access to
req$rook.input$read()
or the parameters parsed infilterFun
. Feasible?I assume (re)setting the values for the DT inputs would be harder. Possible?
The text was updated successfully, but these errors were encountered: