geotheory
geotheory

Reputation: 23690

Immediate re-click on button has no effect

I have a Shiny app that allows user to edit record notes by clicking a button in the table. It works for first click, but immediately after you close the the edit dialogue (OK or cancel) the same button becomes innert. If you click a second button the first then becomes active again. Any idea how to fix this?

require(shiny)
require(DT)
require(tidyverse)

states_dat = tibble(id = state.abb, name = state.name, pop = state.x77[,1], note = NA_character_)

#------------------------------------------------

# Return the UI for a modal dialog with state update options
editModal = function(conv_id) {
  ns = NS('state-update')
  curr_mon_id <<- conv_id
  
  conv = dplyr::filter(my_dt$df, id == conv_id$id)
  modalDialog(
    h3(paste0('Edit note ', conv_id)),
    textInput(ns("edit_note"), "Note", value = conv$note, width='600px'),
    footer = tagList(
      modalButton("Cancel"),
      actionButton(ns("ok"), "OK")
    )
  )
}

#------------------------------------------------

# Main screen server
dt_server = function(input, output, session) {
  ns = session$ns
  myValue = reactiveValues(check = '')
  
  shinyInput = function(FUN, len, id, ns, ...) {
    inputs = character(len)
    for (i in seq_len(len)) inputs[i] = as.character(FUN(paste0(id, i), ...))
    inputs
  }
  
  my_dt <<- reactiveValues(df = {
    dat = states_dat
    dat$` ` = shinyInput(actionButton, nrow(dat), 'button_', label = "Edit note",
                         onclick = glue::glue('Shiny.onInputChange("{ns("select_button")}", this.id)'))
    dat
  })
  
  observeEvent(input$select_button, {
    selectedRow = as.numeric(strsplit(input$select_button, "_")[[1]][2])
    myValue$check <<- my_dt$df[selectedRow,1]
    showModal(editModal(myValue$check))
  })
  
  output$states_table = DT::renderDT(filter = "top", {
    return(my_dt$df)
  }, escape = FALSE)
}

#------------------------------------------------

# Record Update server
mud_server = function(input, output, session) {
  ns = session$ns
  
  # When OK button is pressed, check if details have changed and if so update postgres db
  observeEvent(input$ok, {
    id = curr_mon_id$id[1]
    
    if(!identical(input$edit_note, states_dat$note[states_dat$id == id])){
      my_dt$df$note[my_dt$df$id == id] = input$edit_note
    }
    
    removeModal()
  })
}

#------------------------------------------------

# Data table UI
dt_ui = function(id){
  ns = NS(id)
  
  tagList(
    titlePanel( h3('State populations'), windowTitle = 'States-Pop'), hr(),
    mainPanel(width=12, DT::DTOutput(ns("states_table"))
    )
  )
}

#------------------------------------------------

ui = fluidPage( dt_ui(id = "states-manager"))

server = function(input, output, session) {
  callModule(module = dt_server , id = "states-manager")
  callModule(module = mud_server , id = "state-update")
}

shinyApp(ui = ui, server = server)

Any other brief comments on how to improve this app would be very welcome. This is my first experience of Shiny modules so it be far from an optimal configuration. For instance note edits wipe any current table filters in place..

Upvotes: 2

Views: 64

Answers (1)

thothal
thothal

Reputation: 20409

In your JS you set select_button to the respective id. A consequent click sets it to the same id. Since the value does not change, the observer does not fire again. If you click another button in between, the value changes twice and it works again.

This behaviour is described here.

You can explicitely tell JS to treat a click as an event, rather than setting a value by adding {priority: "event"} as described in the link.

Thus, the following snippet will do the trick:

my_dt <<- reactiveValues(df = {
      dat = states_dat
      dat$` ` = shinyInput(actionButton, nrow(dat), 'button_', label = "Edit note",
                           onclick = glue::glue('Shiny.setInputValue("{ns("select_button")}", this.id, {{priority: "event"}})'))
      dat
   })

Note. I used setInputValue instead of onInputChange as the latter is soft-deprecated in Shiny v 1.1.

Upvotes: 1

Related Questions