1

There is some puzzling behaviour when working with dynamicaly created observeEvents for also dynamically created actionsButtons in a DT::dataTableOutput

Have a look at the following app:

library(shiny)
ui <- fluidPage(
  sidebarLayout(
    sidebarPanel = sidebarPanel(
      textInput("txt","Txt"),
    ),
    mainPanel = mainPanel(
      DT::dataTableOutput("dt")
    )
  )
)

server <- function(input, output, session) {
  observeEvent(input$txt, {
    output$dt <- DT::renderDT(
      data.frame("content" = rep(input$txt, 5),
                 "buttons" = unlist(lapply(1:5, function(i){
                   as.character(
                     actionButton(paste0("ab",i),
                                  label = paste0("ab",i),
                                  onclick = "Shiny.setInputValue(this.id, 42, {priority: 'event'})"
                                  )
                   )
                 }))),
      escape = FALSE
    )
  })
  abObserver <- function(i, message=" is greeting you"){
    print(paste("observeEvent is being created:", i))
    observeEvent(input[[paste0("ab",i)]],{
      print(paste0("observing ab",i," with message: ",message,"~~~~~~~~",input$txt))
    })
  }
  observerlist <- lapply(1:5, abObserver, message = input$txt)
}

shinyApp(ui, server, options = list('launch.browser'=TRUE))

I have a dataTable with actionButtons. They have their own observeEvents: They print the value of input$txt at time of creation of the observeEvent (the message-part of the print) and the input$txt like it is at the time of clicking.

Now please proceed as follows:

  • start the app. You will see in the R-console that all observeEvents are created.
  • enter "qqq" to txt
  • press ab1
  • you will see the output "observing ab1 with message: qqq~~~~~~~~qqq". So far so good.
  • change txt to "qqqttt"
  • now press ab2
  • you will see the output "observing ab2 with message: qqq~~~~~~~~qqqttt"

But at the neither at the time when the observeEvent for ab2 was created nor at the time it was used the first time the input$txt was "qqq". So I am a bit surprised.

Regarding this whole setup I have a few questions:

  • Why do I have to add the onclick = "Shiny.setInputValue(this.id, 42, {priority: 'event'})"? I mean, if I press the button, I press the button so why do I have to tell Shiny again that just pressed the button? The observeEvent is already there, so I do not understand why it is not triggered without the onclick-parameter.
  • When I change the txt then all buttons are rendered again. But somehow input$ab1 is not set back to zero (I saw that using a browser and also that only already pressed buttons are not NULL). How are the buttons working?
  • Is this a usual way to include buttons in your datatable?
Noskario
  • 378
  • 1
  • 9
  • I'd suggest using [Shiny.bindAll](https://community.rstudio.com/t/what-is-the-purpose-of-using-shiny-bindall/14489/2) instead of `Shiny.setInputValue`. Furthermore, please see [this](https://stackoverflow.com/questions/70006107/dt-link-binding-is-lost-after-re-rendering-the-table) related question. – ismirsehregal Mar 07 '23 at 09:04
  • Is it really related to the DT datatable? The behavior is the same without that, no? – Stéphane Laurent Mar 07 '23 at 10:04

1 Answers1

0

Your question is mixing several questions and as such is highly confusing. The question regarding the DT datatable should be separate. And you don't need the five buttons to illustrate the behavior, one is enough:

library(shiny)

ui <- fluidPage(
  br(),
  textInput("txt", "Enter something", value = "INITIAL"),
  br(),
  actionButton("ab", "click me")
)


server <- function(input, output, session) {
  
  abObserver <- function(message) {
    print(paste("observeEvent is being created"))
    observeEvent(input[["ab"]], {
      print(
        paste0("observing ab with message: ", message, "~~~~~~~~", input$txt)
      )
    })
  }
  
  observerlist <- abObserver(message = input$txt)
  
}

shinyApp(ui, server)

When you launch this app, the observer is created but as you can see its body is not executed (you don't see "observing ab..." in the console). That's because the action button it observes is initially 0 and this value does not trigger the observer. So input$txt (="INITIAL") is not read at this moment, in the body of the observer.

Now you write qqq and you click the button, the observer is triggered, its body is executed and input$txt is qqq at this moment.

Now the body of the observer is created, and message is qqq at this moment.

Now why qqq ~~~~~ qqqttt instead of qqqttt ~~~~~ qqqttt? Because message is not reactive. If you use a reactive value (observe the parentheses message()) then you will get qqqttt ~~~~~ qqqttt:

  abObserver <- function(message) {
    print(paste("observeEvent is being created"))
    observeEvent(input[["ab"]], {
      print(
        paste0("observing ab with message: ", message(), "~~~~~~~~", input$txt)
      )
    })
  }
  
  reacval <- reactive(input$txt)
  observerlist <- abObserver(message = reacval)

This is like passing reacval() instead of reacval in a Shiny module, a question that often occurs here.

Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • I can understand why this happens when there is only one single button, but in my example the observer of `ab2` is not (as far as I can tell) triggered when `txt` is "qqq" so this is surprising to me. Is it because the variable `message` is shared among all buttons? But as far as I know this is not true for functions created by `lapply` but only a problem with `for` loops. – Noskario Mar 07 '23 at 10:43
  • @Noskario The observer of `ab2` is triggered only when you click on `ab2`, I don't see the problem. – Stéphane Laurent Mar 07 '23 at 10:47
  • Yes, it is only triggered when you click on it, that's true. I wanted to say that it prints "qqq~~~~qqqttt" although there is not an obvious reason to me why `message` is "qqq" for `ab2` – Noskario Mar 07 '23 at 11:31
  • @Noskario Ah right, that is not clear... let me think. – Stéphane Laurent Mar 07 '23 at 11:44
  • @Noskario That's not happening without the datatable stuff. Still I don't understand. – Stéphane Laurent Mar 07 '23 at 11:57
  • @Noskario Indeed this is related to the fact that `message` is shared, because if you do `abObserver(1, message = input$txt); abObserver(2, message = input$txt)`, the behavior is not this one. – Stéphane Laurent Mar 07 '23 at 12:09