R shiny - last clicked button id
Asked Answered
S

3

3

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.

Sudiesudnor answered 21/10, 2016 at 5:5 Comment(0)
I
7

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)
Impregnable answered 21/10, 2016 at 7:0 Comment(4)
Thanks a lot. Could you also explain, how to save currently selected values in selectInput button? suppose I have selectInput and actionButton 'Save'. For each 'Save' click i want to save currently selected value in selectInput as updateSelectInput, could you add that? If you want, I can add new question.Sudiesudnor
Not exactly, I meant that if selectInput I have choices = c(1:5), selected = 1 and if I change in app selected value to 4 and click 'Save', selectInput button will update its selected value to 4 (so last chosen value before 'Save' button)Sudiesudnor
im really cant understand what you want... may be better will b eto ask new questionImpregnable
please, refer to the question #40171722, I hope it will be more understandable for you.Sudiesudnor
P
5

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)
Plug answered 21/10, 2016 at 6:38 Comment(1)
what if I have 100 actionButtons, how to write so many observeEvents? assume that your buttons starts with 'button'+X, where X is from 1 to 100Sudiesudnor
S
0

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 (e.g., 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?

Strickler answered 16/6, 2021 at 19:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.