简体   繁体   中英

R shiny - last clicked button id

I have multiple action buttons, on which i want to show different select Inputs and I want to know last clicked button id, how can I do that? When I use

which(lapply(c(1:10), function(i) { input[[paste0("ActionButton", i)]]}) == TRUE)

It shows me all button which were clicked, however I want to know which one was the last in order to enable click once again on previous buttons. How can I do that? I am new in shiny and not sure if understand all reactive/isolate issue so I would be greateful for any hints.

You can do it by adding JS

smthing like

$(document).on('click', '.needed', function () {
                              Shiny.onInputChange('last_btn',this.id);
                             });

Example ( add class needed to btn if you want to control not all btn)

 ui <- shinyUI(fluidPage(

  titlePanel("Track last clicked Action button"),
  tags$head(tags$script(HTML("$(document).on('click', '.needed', function () {
                                Shiny.onInputChange('last_btn',this.id);
                             });"))),

  sidebarLayout(
    sidebarPanel(
      actionButton("first", "First",class="needed"),
      actionButton("second", "Second",class="needed"),
      actionButton("third", "Third",class="needed"),
      actionButton("save", "save"),
      selectInput("which_","which_",c("first","second","third"))
    ),

    mainPanel(

      textOutput("lastButtonCliked")
    )
  )
))


server <- shinyServer(function(input, output,session) {
  observeEvent(input$save,{
    updateSelectInput(session,"which_",selected = input$last_btn)
  })
  output$lastButtonCliked=renderText({input$last_btn})

})
# Run the application 
shinyApp(ui = ui, server = server)

This code track which button was last clicked:

   library(shiny)


    ui <- shinyUI(fluidPage(


       titlePanel("Track last clicked Action button"),


       sidebarLayout(
          sidebarPanel(
            actionButton("first", "First"),
            actionButton("second", "Second"),
            actionButton("third", "Third")
          ),

          # Show a plot of the generated distribution
          mainPanel(
             textOutput("lastButtonCliked")
          )
       )
    ))


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

            rv <- reactiveValues(lastBtn = character())
            observeEvent(input$first, {
                    if (input$first > 0 ) {
                            rv$lastBtn = "first"
                    }
            })
            observeEvent(input$second, {
                    if (input$second > 0 ) {
                            rv$lastBtn = "second"
                    }
            })
            observeEvent(input$third, {
                    if (input$third > 0 ) {
                            rv$lastBtn = "third"
                    }
            })
            output$lastButtonCliked <- renderText({
                    paste("Last button clicked: ", rv$lastBtn)
            })
    })
    # Run the application 
    shinyApp(ui = ui, server = server)

Version with lapply with many buttons. Credit goes to @Victorp and this answer .

This is the code:

    library("shiny")
    ui <- fluidPage(
            fluidRow(
                    column(
                            width = 6,
                            lapply(
                                    X = 1:5,
                                    FUN = function(i) {
                                            actionButton(inputId = paste0("button", i), label = paste("Button ", i))
                                    }
                            )
                    ),
                    column(
                            width = 6,
                            textOutput("lastButtonCliked")
                    )
            )
    )
    server <- function(input, output){

            rv <- reactiveValues(lastBtn = character())

            lapply(
                    X = 1:6,
                    FUN = function(i){
                            observeEvent(input[[paste0("button", i)]], {
                                    if (input[[paste0("button", i)]] > 0) {
                                            rv$lastBtn = paste0("button", i)    
                                    }
                            })
                    }
            )

            output$lastButtonCliked <- renderText({
                    paste("Last button clicked: ", rv$lastBtn)
            })
    }
    shinyApp(ui = ui, server = server)

There is a third solution taking advantage of the fact that each button keeps the number of time is has been pressed. If you could monitor that number of time, then any change in that number will indicate which button was pressed.

Here is a short implementation. The page has three buttons (with arbitrary names):

page <- shinyUI(basicPage(
    actionButton("firstbtn",label="Btn1"),
    actionButton("secondbtn",label="Btn2"),
    actionButton("thirdbtn",label="Btn3"),
    textOutput("result")
))

shinyServer <- function(input, output, session) {
    # the number of clicks on each button is zero at first
    oldBtnClicks <- rep(0,3)

    observeEvent({ obs <<- list(input$firstbtn, input$secondbtn, input$thirdbtn) }, ({
        # store all button state in a list
        BtnState <- obs

        # extract in a vector the number of clicks from each
        newBtnClicks <- rep(0,3)
        for (i in 1:3) 
            newBtnClicks[i] <- if (is.null(BtnState[[i]])) 0 else BtnState[[i]][1]

        # look for the change in the number of clicks
        buttonClicked <- match(1, newBtnClicks - oldBtnClicks)

        # show the button number that was clicked
        output$result <- renderText(expr = buttonClicked)
        
        # update hte number of clicks in the shinyServer environment
        oldBtnClicks <<- newBtnClicks

    }))
}

shinyApp(ui = page, server = shinyServer)

The server function first set 0 to each button's click (they have not been pressed yet). Then it sets and observer which looks for any of the button. The list being observed could be of arbitrary length.

When an event occurs, the button states are retrieved in a list (the same as the observed list). From that list, the first elements of each sublist is retrieved (this is the number of clicks on that particular button); if some buttons can be hidden (as was the case in my own application), the list of click is null and the number of click is therefore set to 0 manually.

Finally, by taking the difference between the former state and the new state, the only place which is not zero (found with match ) is the position of the button pressed. Once done, don't forget to update the button state list. Et voilà!

If your buttons have a regular name (eg, BtnX, with X going from 1 to n), then there might be a way to built the observed list programmatically rather than by manually enumerating the buttons?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM