Create Interactive Action Buttons Based on User Input Selection in Shiny Applications

Creating Action Buttons from User Input Selection

In this article, we’ll explore how to create interactive action buttons based on user input selection in a Shiny application. We’ll delve into the world of reactive values, conditionals, and custom UI elements.

Background

Shiny is an R framework for building web applications that incorporate Shiny’s graphical user interface (GUI) components, such as text inputs, dropdown menus, and buttons. The shinyWidgets package provides additional GUI components, including action buttons. These buttons can be customized to respond to different user inputs.

Our goal in this article is to create an interactive application where users can input their name, select countries, cities, or popular items, and receive corresponding ratings.

Step 1: Setting Up the Application

First, we’ll set up a new Shiny application using the shiny package. We’ll also import necessary libraries for data manipulation and visualization.

library(shiny)
library(shinyWidgets)
library(emojifont)
library(shinyBS)

Step 2: Creating UI Components

Next, we’ll create UI components that will collect user input:

  • textInput("name", "Enter your name:"): a text input field for users to enter their name.
  • actionButton("selectCountry", "Select Country"): an action button to select a country.
ui <- fluidPage(
  useShinyjs(),
  titlePanel("Info"),
  
  fluidRow(
    
    column(width = 4,
           panel(
             style = "overflow-y:scroll; max-height: 300px; position:relative; align: centre",
             textInput("name", label = "",
                       placeholder = "Type Message"),
             actionButton("selectCountry", "Select Country"), heading = "Smart-Advisor", status = "primary")
           ))))

Step 3: Creating Server-Side Logic

Now, we’ll write server-side logic to handle user input and create action buttons accordingly.

server <- function(input, output, session) {
  
  # Declaring and Initializing Global Variables
  
  lvl <- reactiveVal()
  lvl(i)
  
  countries <- matrix(c("India", "US", "UK", "Canada"), byrow = TRUE, nrow = 1)
  emj <- reactiveValues(em = 1)
  
  clearInput <- function() {
    updateTextInput(session, "name", value = "")
  }
  
  invalidInput <- function() {
    insertUI(selector = "#name", where = "beforeBegin",
             ui = div(class = "chat-bubbles", div(class = "bubble admin",
                           p("Kindly provide a valid input")))
    clearInput()
  }
  
  cities <- reactive({
    dat %>% filter(Country == "India") %>% distinct(Cities)
  })
  
  popularItems <- reactive({
    dat %>% filter(Country == "India", Cities == "New Delhi") %>% distinct(`Popular for-Item`)
  })
  
  # Main Function
  replyMessage <- function(lvl, msg) {
    switch(lvl,
           # Check for Level 1
           if (grepl("^[a-zA-Z][a-zA-Z ]+[a-zA-Z]$", msg, perl = TRUE)) {
             insertUI(selector = "#name", where = "beforeBegin",
                      ui = div(class = "chat-bubbles", div(class = "bubble admin",
                                                        img(), wellPanel(
                                                          p("Hi,", tags$b(msg), ".", tags$br(),
                                                            "My name is Zeta!"), tags$br()),
                                                        p(actionButton("mood1", "India", icon = icon("grin"),
                                                                     style = "pill", color = "warning", size = "xs"),
                                                        actionButton("mood2", "US", icon = icon("frown-open"),
                                                                 style = "pill", size = "xs", color = "success"),
                                                        actionButton("mood3", "UK", icon = icon("meh"), style = "pill",
                                                                 size = "xs", color = "primary"),
                                                        actionButton("mood4", "Canada", icon = icon("meh"),
                                                                 style = "pill", size = "xs", color = "primary"))),
             clearInput(),
             shinyjs::disable("name"),
             shinyjs::hide("selectCountry")
           },
           
           # Level 3
           if (msg == "India") {
             insertUI(selector = "#name", where = "beforeBegin",
                      ui = div(class = "chat-bubbles", div(class = "bubble admin",
                                                        img(), wellPanel(
                                                          p("What Personal challenges are you facing?", emoji("raising_hand")))), tags$br(),
                                                        p(actionButton("P1", paste(cities()[1, 1]), icon = icon("user-friends"),
                                                                     color = "warning", style = "pill", size = "xs"), tags$br(), tags$br(),
                                                          actionButton("P2", paste(popularItems()[1, 1]), icon = icon("dollar-sign"),
                                                           color = "success", style = "pill", size = "xs"), tags$br(), tags$br(),
                                                          actionButton("P3", paste(cities()[1, 1]), icon = icon("first-aid"),
                                                           color = "primary", style = "pill", size = "xs"))),
             clearInput(),
             shinyjs::disable("name"),
             shinyjs::hide("selectCountry")
           },
           
           if (paste(cities()[1, 1]) == TRUE) {
             insertUI(selector = "#name", where = "beforeBegin",
                      ui = div(class = "chat-bubbles", div(class = "bubble admin",
                                                        img(), wellPanel(
                                                          p("What Personal challenges are you facing?", emoji("raising_hand")))), tags$br(),
                                                        p(actionButton("P1", paste(popularItems()[1, 1]), icon = icon("user-friends"),
                                                                     color = "warning", style = "pill", size = "xs"), tags$br(), tags$br(),
                                                          actionButton("P2", paste(popularItems()[1, 1]), icon = icon("dollar-sign"),
                                                           color = "success", style = "pill", size = "xs"), tags$br(), tags$br(),
                                                          actionButton("P3", paste(popularItems()[1, 1]), icon = icon("first-aid"),
                                                           color = "primary", style = "pill", size = "xs")))
             clearInput(),
             shinyjs::disable("name"),
             shinyjs::hide("selectCountry")
           }
       } )
  
  # Function to Check Blank in Message Box
  getMessage <- function(lvl) {
    observeEvent(input$selectedCountry, {
      if (input$selectedCountry == "") {
        insertUI(selector = "#name", where = "beforeBegin",
                 ui = div(class = "chat-bubbles", div(class = "bubble admin",
                                                   img()), p("Kindly provide a valid input.")))
        clearInput()
      } else {
        replyMessage(lvl(), input$selectedCountry)
      }
    })
    
    lapply(sprintf("mood%s", 1:4),
             function(x) {
               observeEvent(input[[x]], {
                 emj$em <- as.numeric(sub("mood", "", x))
                 insertUI(selector = "#name", where = "beforeBegin",
                          p(paste(replyMessage(lvl(), emojis[, emj$em]))))
               })
               shinyjs::disable("mood1")
               shinyjs::disable("mood2")
               shinyjs::disable("mood3")
               shinyjs::disable("mood4")
             })
  }
  
  # Main Function
  startConversation <- function() {
    clearInput()
    insertUI(selector = "#name", where = "beforeBegin",
             ui = div(class = "chat-bubbles", div(class = "bubble admin", tags$img(src = "chat-robot.gif", class = "img-responsive")),
                      wellPanel(p("Hey! Could I get your name?")))
    getMessage(lvl)
  }
  
  startConversation()
}

Step 4: Integrating Reactive Values

We’ll define reactive values to store the user’s input and update them accordingly.

# Defining Server Controls
server <- function(input, output, session) {
  # ...
  
  # Define a reactive value for the selected country
  selectedCountry <- reactiveValues(em = 1)
  
  # Update the selected country when the "Select Country" button is clicked
  observeEvent(input$selectCountry, {
    updateTextInput(session, "selectedCountry", value = "")
  })
  
  # Use the selected country in the reply message function
  replyMessage <- function(lvl, msg) {
    switch(lvl,
           # ...
           if (input$selectedCountry == "") {
             insertUI(selector = "#name", where = "beforeBegin",
                      ui = div(class = "chat-bubbles", div(class = "bubble admin", img()), p("Kindly provide a valid input.")))
             clearInput()
           } else {
             replyMessage(lvl(), input$selectedCountry)
           }
         })
}

Step 5: Creating Custom UI Components

We can create custom UI components using the shinyWidgets package. For example, we can create a custom button that displays an emoji.

# Create a custom button with an emoji
ui <- fluidPage(
  useShinyjs(),
  titlePanel("Info"),
  
  fluidRow(
    column(width = 4,
           panel(
             style = "overflow-y:scroll; max-height: 300px; position:relative; align: centre",
             textInput("name", label = "",
                       placeholder = "Type Message"),
             actionButton("selectCountry", "Select Country"), heading = "Smart-Advisor", status = "primary")
           ))
)

# Create a custom button with an emoji
ui <- fluidPage(
  useShinyjs(),
  titlePanel("Info"),
  
  fluidRow(
    column(width = 4,
           panel(
             style = "overflow-y:scroll; max-height: 300px; position:relative; align: centre",
             textInput("name", label = "",
                       placeholder = "Type Message"),
             actionButton("selectCountry", "Select Country"), heading = "Smart-Advisor", status = "primary")
           ))
  
  # Display a custom button with an emoji
  div(class = "button-container", shiny::actionButton("customButton", "", icon = shiny::icon("smile")))
)

Conclusion

In this article, we’ve explored how to create interactive action buttons based on user input selection in a Shiny application. We’ve used reactive values and custom UI components to make the application more engaging and user-friendly.

Example Use Cases

  1. Chatbot Application: Create a chatbot that responds to user inputs with relevant answers or actions.
  2. Survey Application: Develop an interactive survey application where users can select options and receive feedback based on their responses.
  3. Game Development: Build games that require user input, such as button presses or key presses, to progress through levels or challenges.

Tips and Variations

  1. Use conditionals: Use if statements or conditional expressions to make your application more dynamic and responsive to user inputs.
  2. Create custom UI components: Use the shinyWidgets package to create custom UI components that fit your application’s design and functionality.
  3. Incorporate reactive values: Use reactive values to store and update data in real-time, allowing for a more interactive and dynamic user experience.

By following these steps and incorporating tips and variations, you can create engaging and interactive applications using Shiny that respond to user inputs and provide a unique experience for your users.


Last modified on 2024-08-11