If you run the app below, it works fine at the beginning: you can reorder the rows of mtcars
and the order appears in the verbatimTextOutput
. But once you change the data to iris
with the radio button, that does not work anymore.
library(shiny)
library(shinyjqui)
ui <- fluidPage(
radioButtons("radio", "Data", choices = c("mtcars", "iris")),
verbatimTextOutput("rows"),
sortableTableOutput("tbl")
)
server <- function(input, output) {
Dat <- reactive({
if(input[["radio"]] == "mtcars") {
mtcars
} else {
iris
}
})
output[["rows"]] <- renderPrint({ input[["tbl_order"]] })
output[["tbl"]] <- renderTable(Dat(), rownames = TRUE)
}
shinyApp(ui, server)
With the app below, using a renderUI
reacting to the radio button, this is slightly better: this works as expected sometimes.
library(shiny)
library(shinyjqui)
ui <- fluidPage(
radioButtons("radio", "Data", choices = c("mtcars", "iris")),
verbatimTextOutput("rows"),
uiOutput("tblUI")
)
server <- function(input, output) {
Dat <- reactive({
if(input[["radio"]] == "mtcars"){
mtcars
}else{
iris
}
})
output[["rows"]] <- renderPrint({input[["tbl_order"]]})
output[["tbl"]] <- renderTable(Dat(), rownames = TRUE)
output[["tblUI"]] <- renderUI({
Dat()
sortableTableOutput("tbl")
})
}
shinyApp(ui, server)
What can we do to get an app which correctly works? Maybe an alternative to shinyjqui::sortableTabbleOutput
?
CodePudding user response:
You are close, but a little more needs to be done. This will work:
library(shiny)
library(shinyjqui)
ui <- fluidPage(
radioButtons("radio", "Data", choices = c("mtcars", "iris")),
verbatimTextOutput("rows"),
uiOutput("tblUI")
)
server <- function(input, output) {
Dat <- reactive({
if(input[["radio"]] == "mtcars"){
tbl_id(0)
mtcars
}else{
tbl_id(1)
iris
}
})
tbl_id <- reactiveVal(0)
output[["rows"]] <- renderPrint({input[[paste0("tbl", tbl_id(), "_order")]]})
observe({
output[[paste0("tbl", tbl_id())]] <- renderTable(Dat(), rownames = TRUE)
})
output[["tblUI"]] <- renderUI({
Dat()
sortableTableOutput(paste0("tbl", tbl_id()))
})
}
shinyApp(ui, server)
Let me explain why.
- In the
sortableTableOutput
function, you can see there is some JS code that will be run. The script binds the table to a sortable event and binds to shiny. Not entirely sure how jqui sets shiny input, but from this$.map(idx ...
I guess the listener is added to each row element. - Then, here comes the second problem. If you set up the new table rows with sortable event, it has a target
shinyjqui.msgCallback({"ui":"[id='tbl']"
. This is the same ID as the old table. Both tables' rows are pointing to the same ID, so ID conflicting usually causes trouble. This is my guess why it gives youNULL
. - Once we know the cause, the solution is pretty straightforward. We bind two tables to different IDs, when generating the container, we just name them differently, and it worked! As an experienced Shiny user like you, I believe there is no need to explain the code details.
- The
destroy
option you suggested will not work, because the sortable is applied on each row, you would need to applynrow
times of destroy, and it cannot avoid the ID conflict problem.
I think this is a critical feature that this package is missing. I would recommend filing an issue on Github.