shinyjs is not excecuting all actions inside observeEvent

34 Views Asked by At

I got an app that when you click on an actionButton, it should set an input to a certain value; and a click action should be made through shinyjs. However, only the first thing is happening; and I don't know how to make the second one happen. Or maybe it IS happening; but the data inside the reactive object is not getting updated.

Heres a minimal reprex:

library(shiny)

ui <- fluidPage(
  shinyjs::useShinyjs(),
  
  selectInput("selector", label = "Carb selector", choices = unique(mtcars$carb)),
  actionButton("generate", "OK!"),
  tableOutput("results"),
  actionButton("reset", "RESET"),
  
)

server <- function(input, output, session) {
  
  data <- reactive({
    req(input$generate)
    isolate(
    mtcars %>% filter(carb == input$selector)
    )
  })
  
  output$results <- renderTable(data())

  observeEvent(input$reset, {
    
    updateSelectInput(session, 
                      inputId = "selector",
                      label = "Carb selector updated",
                      choices = unique(mtcars$carb),
                      selected = 1)
    
    shinyjs::click("generate")#This does not seem trigger when you hit reset!
    
  })
    
}

shinyApp(ui, server)
2

There are 2 best solutions below

0
Mwavu On BEST ANSWER

Why this behavior?

The architecture of your code is a bit questionable, but I will point out why it is behaving this way.

To understand this, let's first break the observer on input$reset into two:

  observeEvent(input$reset, {
    updateSelectInput(
      session,
      inputId = "selector",
      label = "Carb selector updated",
      choices = unique(mtcars$carb),
      selected = 1
    )
  })

  observeEvent(input$reset, {
    shinyjs::click("generate") # This does not seem trigger when you hit reset!
  })

After that, let's have a look at the documentation of updateSelectInput:

The input updater functions send a message to the client, telling it to change the settings of an input object. The messages are collected and sent after all the observers (including outputs) have finished running.

And there lies the answer. In other words, shinyjs::click("generate") will always execute before update*Input() effects kick in.

Basically, this is the flow:

1. User clicks 'reset' btn
2. That leads to a click on 'generate' btn
3. The `data()` reactive is re-evaluated
4. All observers are re-evaluated
5. `update*Input()` sends updates to the client

Suggested solution

We can use number 4 above to our advantage by having a reactiveVal() that always has the most current value of 'selector' and is a step ahead of update*Input().

I have made a few changes to your code to make it more explicit and straight to the point.

Demo

library(shiny)
library(dplyr)

ui <- fluidPage(
  shinyjs::useShinyjs(),
  selectInput("selector", label = "Carb selector", choices = unique(mtcars$carb)),
  actionButton("generate", "OK!"),
  tableOutput("results"),
  actionButton("reset", "RESET"),
)

server <- function(input, output, session) {
  rv_selector <- reactiveVal()
  observeEvent(input$selector, rv_selector(input$selector))

  data <- reactive({
    mtcars %>% filter(carb == rv_selector())
  }) |> bindEvent(input$generate)

  output$results <- renderTable(data())

  observeEvent(input$reset, {
    updateSelectInput(
      session,
      inputId = "selector",
      label = "Carb selector updated",
      choices = unique(mtcars$carb),
      selected = 1
    )
    rv_selector(1) # Ensures server is updated before the client
    shinyjs::click("generate")
  })
}

shinyApp(ui, server)
2
YBS On

It is triggering, but you don't see it in your dataset as you are not changing anything. Try this

library(shiny)

ui <- fluidPage(
  shinyjs::useShinyjs(),

  selectInput("selector", label = "Carb selector", choices = unique(mtcars$carb)),
  actionButton("generate", "OK!"),
  tableOutput("results"),
  actionButton("reset", "RESET"),

)

server <- function(input, output, session) {

  data <- reactive({ 
    req(input$generate)
    # isolate(
      mtcars %>% filter(carb == input$selector) %>%
        dplyr::mutate(clickedtimes = input$generate)
    # )
  })

  output$results <- renderTable(data())

  observeEvent(input$reset, {

    updateSelectInput(session,
                      inputId = "selector",
                      label = "Carb selector updated",
                      choices = unique(mtcars$carb),
                      selected = 1)

    shinyjs::click("generate")#This does not seem trigger when you hit reset!

  })
  observe({print(input$generate)})
}

shinyApp(ui, server)