I have this small app.
I am dividing a dataframe in slices, using a previous and next button I am iterating showing the different slices of it in a datatable.
Inside the datatable I have checkboxes, their IDs are reset programmatically as soon as the new slice is requested.
From a tibble with 30 rows:
- I select the subset of it with a reactive value
- I define the checkboxes IDs
- I display the table
- I observe the inputs with lapply, at the first render they are setup properly, when changing a checkbox it is printed in the console
- then I press the next button, a new table is rendered, the lapply function run again but this time the observers don't work anymore
the first display works, as soon as it changes I need a way to reset the observers.
sample code:
library("DT")
library("shinyjs")
library("tidyverse")
library("shiny")
ui <- basicPage(
h2("The mtcars data"),
useShinyjs(),
actionButton("prv", "prv", icon("arrow-left")),
actionButton("nxt", "nxt", icon("arrow-right")),
DT::dataTableOutput("mytable")
)
server <- function(input, output) {
###Sample Data
mtcarsx <- reactive(
data.frame(mtcars) %>%
as_tibble() %>%
mutate( slice=round(runif(row_number(),min=1,max=5)) )
)
###Slice selector that will be modified with the button
sliceN <- reactiveVal(1)
###Manipulating the slice
thisSlice <- reactive({
mtcarsx() %>%
filter(slice==sliceN()) %>%
mutate(rown=row_number()) %>%
rowwise() %>%
mutate(
randmz=runif(row_number(),min=0,max=3),
newvar=case_when(
#I have checkboxes defaulted to true, checkboxes defaulted to false, checkboxes defaulted to true that I will disable
randmz < 1 ~ as.character(checkboxInput(paste0("chk",rown),label="",value=TRUE)),
randmz < 2 ~ as.character(checkboxInput(paste0("chk",rown),label="",value=FALSE)),
TRUE ~ as.character(checkboxInput(paste0("chk",rown),label="",value=TRUE))
),
mytype=case_when(
#I have checkboxes defaulted to true, checkboxes defaulted to false, checkboxes defaulted to true that I will disable
randmz < 1 ~ "MYTRUE",
randmz < 2 ~ "MYFALSE",
TRUE ~ "DISABLED"
)
)
})
#to disable checkboxes
observe({
print(input$chk1)
n <- nrow(thisSlice())
lapply(1:n, function(i){if(thisSlice()$mytype[i]=="DISABLED"){ shinyjs::disable(paste0("chk",i)) } })
})
#to listen to checkboxes
observeEvent(input,{
print(input$chk1)
n <- nrow(thisSlice())
lapply(
1:n,
function(i){
observeEvent(input[[paste0("chk",i)]],{
print(paste0("chk",i))
#print(input[[paste0("chk",i)]])
})
})
})
#previous and next buttons
observeEvent(input$nxt, {
sliceN(sliceN()+ 1)
})
observeEvent(input$prv, {
sliceN(sliceN()- 1)
})
#display
output$mytable = DT::renderDataTable({
#print(thisSlice())
DT::datatable(thisSlice(),
escape = FALSE,
selection = 'none',
rownames = TRUE,
extensions = c('FixedColumns'),
options = list(searching = FALSE,
ordering = FALSE,
autoWidth = TRUE,
scrollX = TRUE,
FixedColumns = list(leftColumns = c(2)),
preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
))
})
}
shinyApp(ui, server)
how can I reset the observers when "next" is pressed and after the render of the datatable?
I also tried triggering the event after draw with a javascript callback like this:
observeEvent(input$mycback,{
print("received")
o$destroy
o
})
o<-observeEvent(input,{
same as before
})
and in the dt callback
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); Shiny.setInputValue("mycback","drawn", {priority: "event"})} '),
pasting the disable code inside my callback I've been able to call the disable function after redraw of the table successfully!! big success.
still the observers can listen for changes ONLY at the first draw, I can't explain why.
this is xposted from stackoverflow