Datatable refreshing when modal windows shows refresh button

Hi,

I have a shiny application that shows a datatable. The user can interact with the table contents by pressing some buttons. But some button display a modal dialog (to collect input, e.g.), and the table should refresh only when the user clicks a 'Submit' button in the modal window. The problem is, the datatable is refreshed as soon as the modal is shown, not only when the button is pressed! This makes assessing information from selected rows problematic, because the refreshed table de-selects all rows.

(Edit: I need to refresh the datatable because the user edit data in a database backend)

I believe this problem happens due to the way I am making the table reactive to the buttons. I am linking the output to the buttons directly in the renderDataTable function, as in the example below. The main reason I'm using this instead of a 'observe*' function is because I have many events that should trigger the update, and this way seems easier to implement.

Is there a better way to code the datatable update if I have multiple events that should trigger the update?

library(shiny)
library(DT)

ui <- fluidPage(

    titlePanel("Test DT"),

    sidebarLayout(
        sidebarPanel(
            actionButton('refresh', 'Refresh Table'),
            actionButton('modal', 'Show modal')
        ),
        mainPanel(
           DT::dataTableOutput('table')
        )
    )
)

server <- function(input, output) {

    observeEvent(input$modal, {
        showModal(modalDialog('Simple modal dialog.', footer=actionButton('refresh2', 'Refresh too')))
    })
    
    observeEvent(input$refresh2, {
        removeModal()
    })
    
    output$table <- DT::renderDataTable({
        input$refresh
        input$refresh2
        
        DT::datatable(iris)
    })
}

shinyApp(ui = ui, server = server)

Hi,

The reason it's not working is because the data should be in a reactive format, so different Shiny functions can access it, but you must also prevent it from triggering an update when it changes by isolating it in the render function. This way the table on the screen will only update when any of the buttons is pressed because they activate the render function (input triggers are inside function).

There are other ways to clean this up, but I tried to keep most of your original structure:

library(shiny)
library(DT)

ui <- fluidPage(
  
  titlePanel("Test DT"),
  
  sidebarLayout(
    sidebarPanel(
      numericInput("chooseNumber1", "Choose value to add", value = 2),
      actionButton('refresh', 'Refresh Table'),
      actionButton('modal', 'Show modal')
    ),
    mainPanel(
      DT::dataTableOutput('table')
    )
  )
)

server <- function(input, output) {
  
  myData = reactiveVal(iris)
  
  observeEvent(input$modal, {
    showModal(modalDialog('Simple modal dialog.', numericInput("chooseNumber2", "Choose value to multiply", value = 2), 
                          footer= list(actionButton('refresh2', 'Refresh too'), modalButton("Dismiss")), easyClose = T))
  })
  
  observeEvent(input$refresh,  {
    myData(myData()[,1:4] + input$chooseNumber1)
  })
  
  observeEvent(input$refresh2,  {
    removeModal()
    myData(myData()[,1:4] * input$chooseNumber2)
  })
  
  output$table <- DT::renderDataTable({
    input$refresh
    input$refresh2
    
    DT::datatable(isolate(myData()))
  })
}

shinyApp(ui = ui, server = server)

Let me kow what you think,
PJ

1 Like

PJ,

Thank you for your suggestion! Indeed, this way it works just as I expected.

I am currently trying another solution using dataTableProxy() and replaceData(), defined inside each button observeEvent -- which seems to work fine as well, but your solution is much closer to my original code and works just as fine.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.