Update label of actionButton in shiny - r

I know that similar question was already answered, however the solution creates a new actionButton with different label upon string-input. What I need is to keep the button(the counter of the button), because when I change the label and create a new button it has a counter of 0(not clicked).
So basically I need something like an update function to just change the label of the actionButton, when it is pressed. You press it once and the label changes.
input$Button <- renderUI({
if(input$Button >= 1) label <- "new label"
else label <- "old label"
actionButton("Button", label = label)
})
Something like this, but without reseting the value of the button(by creating a whole new one).
Thanks!

reactiveValues() can help. Check http://shiny.rstudio.com/articles/reactivity-overview.html for details.
In the following example, I renamed your input$Button to input$click to avoid double usage of the "Button" name.
Since we wrap the label in a renderUI(), input$click initially fires once it is created?!?, that's why I put the label
condition as: if(vars$counter >= 2)
An alternative solution could be to remove the read-only attribute (found here: https://github.com/rstudio/shiny/issues/167)
attr(input, "readonly") <- FALSE
input$click <- 1
For an example
paste the following in your R console:
ui <- bootstrapPage(
uiOutput('Button')
)
server <- function(input, output) {
# store the counter outside your input/button
vars = reactiveValues(counter = 0)
output$Button <- renderUI({
actionButton("click", label = label())
})
# increase the counter
observe({
if(!is.null(input$click)){
input$click
isolate({
vars$counter <- vars$counter + 1
})
}
})
label <- reactive({
if(!is.null(input$click)){
if(vars$counter >= 2) label <- "new label"
else label <- "old label"
}
})
}
# run the app
shinyApp(ui = ui, server = server)

You can use updateActionButton from native shiny package:
ui <- fluidPage(
actionButton('someButton', ""),
h3("Button value:"),
verbatimTextOutput("buttonValue"),
textInput("newLabel", "new Button Label:", value = "some label")
)
server <- function(input, output, session) {
output$buttonValue <- renderPrint({
input$someButton
})
observeEvent(input$newLabel, {
updateActionButton(session, "someButton", label = input$newLabel)
})
}
shinyApp(ui, server)

A few years later some small addition: If you want to switch between button icons, e.g. play / pause button (and switching between labels would be similar) you could do something like this (based on shosaco's answer).
library(shiny)
ui <- fluidPage(
fluidRow(
actionButton("PlayPause", NULL, icon = icon("play"))
)
)
server <- function(input, output, session) {
# whenever the ActionButton is clicked, 1 is added to input$PlayPause
# check if input$PlayPause is even or odd with modulo 2
# (returns the remainder of division by 2)
observeEvent(input$PlayPause, {
if (input$PlayPause %% 2 != 0) {
updateActionButton(session, "PlayPause", NULL, icon = icon("pause"))
} else {
updateActionButton(session, "PlayPause", NULL, icon = icon("play"))
}
})
}
shinyApp(ui = ui, server = server)

Related

How to make input$action starts from zero every time I click on Action Buttom in Shiny?

As this link says about Action Button, the input$action return the number of clicks
On the button.
enter link description here
My question is:
How can I, after x-clicks, store the x value in a data frame and make the button starts from zero(actually make input$action starts from zero) and after y-clicks store the y value on this same dataframe and on on and on…?
In other words:
I click 3 times , the input$action sends me the value 3, I store this value, and starts again(somehow, I need to make input$action come back to zero), clicking 8 times the input$action sends me the value 8 I store again e keeps going….
It may be simpler to not use the value of the actionButton directly and just record the number of clicks between events in an external reactiveValues object. This for example has two buttons, one to increase the value and another to add the final value to a vector and reset the counter:
library(shiny)
ui <- fluidPage(
actionButton("action", label = "Action"),
actionButton("store", label = "Store"),
hr(),
fluidRow(column(2, verbatimTextOutput("value")))
)
server <- function(input, output) {
values <- reactiveValues(curr = 0,
out = integer())
observeEvent(input$action, {
values$curr = values$curr + 1
})
observeEvent(input$store, {
values$out <- c(values$out, isolate(values$curr))
values$curr <- 0
})
output$value <- renderPrint({
values$out
})
}
shinyApp(ui, server)
Created on 2022-01-06 by the reprex package (v2.0.1)
If we really need to "reset" the button, we can re-render it. Here is an example app:
library(shiny)
library(dplyr)
ui <- fluidPage(
uiOutput("action"),
actionButton("reset", "Reset"),
verbatimTextOutput("values")
)
server <- function(input, output, session) {
output$action <- renderUI({
actionButton("action_but", "Action")
})
vals <- reactiveVal(tibble(clicks = integer(0)))
counter <- reactiveVal(0)
observe({
counter(input$action_but)
})
observeEvent(input$reset,
{
vals(add_row(vals(), clicks = as.integer(input$action_but)))
output$action <- renderUI({
actionButton("action_but", "Action")
})
counter(input$action_but)
},
ignoreInit = TRUE
)
output$values <- renderPrint({
list(counter(), vals())
})
}
shinyApp(ui, server)
The input$button is read only, so you can't reset the input$button increment without resetting the entire app, which would cause you to lose your saved values. Alternatively, you can keep a copy of the values and reset the count on your copy.
Not sure what you want to do with the reset, but you can still count the number of button presses between your steps, 3, 8 etc. So 8 button presses from 3 would be at input$button == 11.
library(shiny)
ui <- fluidPage(
# Copy the line below to make an action button
actionButton("action", label = "Action"),
hr(),
fluidRow(column(2, verbatimTextOutput("value")),
column(6, verbatimTextOutput("countOutput")))
)
server <- function(input, output) {
# You can access the value of the widget with input$action, e.g.
output$value <- renderPrint({ input$action })
df <- reactiveValues(three = NULL, eight = NULL, thirteen = NULL)
observe({
presses <- c(3, 8, 16)
if(is.null(input$action)){
} else if(input$action == presses[1] & is.null(df$three)) {
df$three = input$action
} else if(input$action == presses[2] & is.null(df$eight)){
df$eight = input$action - presses[1]
} else if(input$action == presses[3] & is.null(df$thirteen)) {
df$thirteen = input$action - presses[2]
}
})
output$countOutput <- renderPrint({
paste(df$three[1], df$eight[1], df$thirteen[1])
})
}
shinyApp(ui, server)

adding a count button to a shiny app that interacts with updateNumericInput

I am building a shiny app and I need a count button to be added that interacts with the numeric input. So I want a numeric input which users can freely use, but that also has a button that users can click that adds 1 to the numeric input (so if a user selects 20, and clicks the button the input becomes 21). I have both working separately, but can't get the interaction to work. The numeric input updates with the add button, but if I change the value with the add numeric input the simply continues at the number of clicks thus far. This is what I now have:
library(shiny)
# https://shiny.rstudio.com/reference/shiny/1.3.2/updateNumericInput.html
# https://gist.github.com/aagarw30/69feeeb7e813788a753b71ef8c0877eb
ui <- shinyUI(
fluidPage(
tags$b("Simple counter using reactiveValues() - An example"),
numericInput("inNumber", "Input number", 0),
actionButton("add1", "+ 1"),
plotOutput("plot")
)
)
server <- function(input, output, session) {
counter <- reactiveValues(countervalue = 0) # Defining & initializing the reactiveValues object
observeEvent(input$add1, {
counter$countervalue <- counter$countervalue + 1 # if the add button is clicked, increment the value by 1 and update it
})
observeEvent(input$add1, {
updateNumericInput(session, "inNumber", value = counter$countervalue )
})
output$plot <- renderPlot({
hist( rnorm(input$add1))
})
}
shinyApp(ui, server)
Maybe this is closer to what you are looking for. You can use one observeEvent for input$add1 button (to increase the counter), and another observeEvent for input$inNumber (set set counter to the numericInput). Your hist could then reference the counter.
server <- function(input, output, session) {
counter <- reactiveValues(countervalue = 0) # Defining & initializing the reactiveValues object
observeEvent(input$add1, {
counter$countervalue <- counter$countervalue + 1 # if the add button is clicked, increment the value by 1 and update it
updateNumericInput(session, "inNumber", value = counter$countervalue)
})
observeEvent(input$inNumber, {
counter$countervalue <- input$inNumber
})
output$plot <- renderPlot({
if (counter$countervalue > 0) {
hist(rnorm(counter$countervalue))
}
})
}
You have to reference the numeric input in the histogramm:
library(shiny)
# https://shiny.rstudio.com/reference/shiny/1.3.2/updateNumericInput.html
# https://gist.github.com/aagarw30/69feeeb7e813788a753b71ef8c0877eb
ui <- shinyUI(
fluidPage(
tags$b("Simple counter using reactiveValues() - An example"),
numericInput("inNumber", "Input number", 0),
actionButton("add1", "+ 1"),
plotOutput("plot")
)
)
server <- function(input, output, session) {
counter <- reactiveValues(countervalue = 0) # Defining & initializing the reactiveValues object
observeEvent(input$add1, {
counter$countervalue <- input$inNumber + 1 # if the add button is clicked, increment the value by 1 and update it
updateNumericInput(session, "inNumber", value = counter$countervalue )
})
output$plot <- renderPlot({
hist( rnorm(input$inNumber))
})
}
shinyApp(ui, server)

Is there a way to dynamically insert / Add UI in a fluidRow in a Shiny app

I am trying to create a shiny app that allows me dynamically add UI control widget. However, the current code would add a new row for each new UI widget. Is there a way to add them into a fluidRow, so that each row would take up to 4 widgets.
Also, is there a way to add/remove control widgets without defaulting all the current selections? The code I have right now basically regenerate the control widgets everything time "Add" or "Remove" button is hit, which means all the selection will reset to default.
Thank you a lot for your help.
The code is as following.
Thank you!
library(shiny)
ui <- shinyUI(fluidPage(
mainPanel(
actionButton("add_btn", "Add Box"),
actionButton("rm_btn", "Remove Box"),
uiOutput("interactionUI"))
))
server <- shinyServer(function(input, output, session) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
observeEvent(input$add_btn, {counter$n <- counter$n + 1})
observeEvent(input$rm_btn, {
if (counter$n > 0) counter$n <- counter$n - 1
})
interaction <- reactive({
n <- counter$n
if (n > 0) {
lapply(seq_len(n), function(i) {
selectInput(inputId = paste0("item", i),
label = paste0("Item", i), choices=c("test","test2"),
selected = NULL,
multiple = 8, selectize = TRUE, width = "20%", size = NULL)
})
}
})
output$interactionUI <- renderUI({ interaction() })
})
shinyApp(ui, server)
Add an id tagged div inside of a fluid row then reference this id as the selector to insert a column.
fluidRow(tags$div(id="rowLabel",column(4,"Example1",textOutput("example1"))))
insertUI(selector = "#rowLabel",where = "afterEnd",ui = tags$div(id="columnLabel",column(4,"Example2",textOutput("example2"))))
I add the div id wrapper to the inserted column to make it easy to delete later.
I understand that this is an old question, but I just had the same problem and thought it would be nice to share my solution for it.
I took inspiration from: https://www.r-bloggers.com/dynamic-ui-elements-in-shiny/
Basically, you should store the UI elements from the lapply call in a variable, and then use a do.call() with your preferred Shiny layout (in my case, flowLayout generated a better result than fluidRow).
library(shiny)
ui <- shinyUI(fluidPage(
mainPanel(
actionButton("add_btn", "Add Box"),
actionButton("rm_btn", "Remove Box"),
uiOutput("interactionUI"))
))
server <- shinyServer(function(input, output, session) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
observeEvent(input$add_btn, {counter$n <- counter$n + 1})
observeEvent(input$rm_btn, {
if (counter$n > 0) counter$n <- counter$n - 1
})
output$interactionUI <- renderUI({
n <- counter$n
if (n > 0) {
interaction <- lapply(seq_len(n), function(i) {
selectInput(inputId = paste0("item", i),
label = paste0("Item", i), choices=c("test","test2"),
selected = NULL,
multiple = 8, selectize = TRUE, width = "20%", size = NULL)
})
}
do.call(flowLayout, interaction)
})
})
shinyApp(ui, server)

Capture the label of an actionButton once it is clicked

Is it possible to capture the label of an actionButton once it is clicked?
Imagine I have 3 buttons on my ui.R and depending on which one I click I want to perform a different action on the server.R.
One caveat is that the buttons are created dynamically on the server.R with dynamic labels (thus the necessity of capturing the label on click)
Thanks
Something like that ?
library(shiny)
server <- function(input, session, output) {
output$printLabel <- renderPrint({input$btnLabel})
}
ui <- fluidPage(
actionButton("btn1", "Label1",
onclick = "Shiny.setInputValue('btnLabel', this.innerText);"),
actionButton("btn2", "Label2",
onclick = "Shiny.setInputValue('btnLabel', this.innerText);"),
verbatimTextOutput("printLabel")
)
shinyApp(ui = ui, server = server)
1) What button was clicked last by the user?
To answer this you can user observeEvent function and by setting up a a variable using reactiveValues function. Make sure you update your libraries and work in the latest version of R (version 3.1.3) as shiny is dependant on this version. Working on windows you can follow example on how to update here
rm(list = ls())
library(shiny)
ui =fluidPage(
sidebarPanel(
textInput("sample1", "Name1", value = "A"),
textInput("sample2", "Name2", value = "B"),
textInput("sample3", "Name3", value = "C"),
div(style="display:inline-block",uiOutput("my_button1")),
div(style="display:inline-block",uiOutput("my_button2")),
div(style="display:inline-block",uiOutput("my_button3"))),
mainPanel(textOutput("text1"))
)
server = function(input, output, session){
output$my_button1 <- renderUI({actionButton("action1", label = input$sample1)})
output$my_button2 <- renderUI({actionButton("action2", label = input$sample2)})
output$my_button3 <- renderUI({actionButton("action3", label = input$sample3)})
my_clicks <- reactiveValues(data = NULL)
observeEvent(input$action1, {
my_clicks$data <- input$sample1
})
observeEvent(input$action2, {
my_clicks$data <- input$sample2
})
observeEvent(input$action3, {
my_clicks$data <- input$sample3
})
output$text1 <- renderText({
if (is.null(my_clicks$data)) return()
my_clicks$data
})
}
runApp(list(ui = ui, server = server))
2) Save the clicks for further manipulation is below
Here's small example based on the work of jdharrison from Shiny UI: Save the Changes in the Inputs and the shinyStorage package.
rm(list = ls())
#devtools::install_github("johndharrison/shinyStorage")
library(shinyStorage)
library(shiny)
my_clicks <- NULL
ui =fluidPage(
#
addSS(),
sidebarPanel(
textInput("sample_text", "test", value = "0"),
uiOutput("my_button")),
mainPanel(uiOutput("text1"))
)
server = function(input, output, session){
ss <- shinyStore(session = session)
output$my_button <- renderUI({
actionButton("action", label = input$sample_text)
})
observe({
if(!is.null(input$sample_text)){
if(input$sample_text != ""){
ss$set("myVar", input$sample_text)
}
}
})
output$text1 <- renderUI({
input$action
myVar <- ss$get("myVar")
if(is.null(myVar)){
textInput("text1", "You button Name")
}else{
textInput("text1", "You button Name", myVar)
}
})
}
runApp(list(ui = ui, server = server))

R Shiny checkboxGroupInput - select all checkboxes by click

I have a R Shiny app that contains checkboxGroupInput, and I'm trying to create a "select all" button, using updateCheckboxGroupInput function.
You can see the full code below, but basically I defined the cb groups like this:
checkboxGroupInput("campaigns","Choose campaign(s):",campaigns_list)
and then, on a button click, call the function:
updateCheckboxGroupInput(session,"campaigns","Choose campaign(s):",choices=campaigns_list,selected=campaigns_list)
I have an indication that the function ran, but what it does is actually UNselecting the checkboxes.
BTW, when I put the selected upon defining the cbGroupInput it did worked, but not on the function.
Thanks!
this is my server.R:
library(shiny)
source('usefulFunctions.R')
shinyServer(function(input, output, session) {
output$cascading <- renderUI({
provider_id <- input$provider
if (provider_id == "") return(NULL)
campaigns_list <<- t(getCampaigns(provider_id))
tagList(
checkboxGroupInput("campaigns","Choose campaign(s):",
choices = campaigns_list, selected = campaigns_list),
actionLink("selectall","Select All")
)
})
observe({
if(is.null(input$selectall)) return(NULL)
if (input$selectall > 0)
{
print(campaigns_list)
updateCheckboxGroupInput(session,"campaigns","Choose campaign(s):",choices=campaigns_list,selected=campaigns_list)
}
})
})
I also added the select and unselect options here by checking if the button or link are divisible by 2
#rm(list = ls())
library(shiny)
campaigns_list <- letters[1:10]
ui =fluidPage(
checkboxGroupInput("campaigns","Choose campaign(s):",campaigns_list),
actionLink("selectall","Select All")
)
server = function(input, output, session) {
observe({
if(input$selectall == 0) return(NULL)
else if (input$selectall%%2 == 0)
{
updateCheckboxGroupInput(session,"campaigns","Choose campaign(s):",choices=campaigns_list)
}
else
{
updateCheckboxGroupInput(session,"campaigns","Choose campaign(s):",choices=campaigns_list,selected=campaigns_list)
}
})
}
runApp(list(ui = ui, server = server))
If campaigns_list is a list, might be because you are specifying the list of all your choices instead of the value of the boxes that should be selected in the selected argument of your updateCheckboxGroupInput.
Try replacing selected=campaigns_list by selected=unlist(campaigns_list).
Here is an example with dummy names:
library(shiny)
server<-function(input, output,session) {
observe({
if(input$selectall == 0) return(NULL)
else if (input$selectall > 0)
{
variables<-list("Cylinders" = "cyl","Transmission" = "am","Gears" = "gear")
updateCheckboxGroupInput(session,"variable","Variable:",choices=variables,selected=unlist(variables))
}
})
}
ui <- shinyUI(fluidPage(
checkboxGroupInput("variable", "Variable:",list("Cylinders" = "cyl","Transmission" = "am","Gears" = "gear")),
actionButton("selectall", "Select All")
))
shinyApp(ui = ui, server = server)

Resources