ixodid
ixodid

Reputation: 2400

Pre-select checkboxes when also allowing all/none checkbox in Shiny checkbox columns

I have implemented two columns with an all/none checkbox. Now I wish to be able to have some of the checkboxes pre-selected using, selected_states, when the app starts.

The normal method of using selected = fails because of how the all/none selector is implemented.

How can I keep the all/none functionality AND allow pre-selection of checkboxes?

library(shiny)
library(shinyWidgets)
library(tidyverse)

df <- tibble(
  state = c("Alabama", "Alaska", "Arizona", "Arkansas",
            "California", "Colorado", "Connecticut", "Delaware", "Florida",
            "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa",
            "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts",
            "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana",
            "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico",
            "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma",
            "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota",
            "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington",
            "West Virginia", "Wisconsin", "Wyoming")
)

selected_states <- c("Alabama", "Alaska","Minnesota")
  
ui <- fluidPage(
 
  wellPanel(
    checkboxInput('all_none', 'All/None'),
    tags$label("Choose :"),
    fluidRow(
      column(
        width = 4,
        checkboxGroupInput(
          selected = selected_states,
          inputId = "checka",
          label = NULL,
          choices = df$state[1:13]
        )
      ),
      
      column(
        width = 4,
        checkboxGroupInput(
          selected = selected_states,
          inputId = "checkb",
          label = NULL,
          choices = df$state[14:25]
        )
      )
    )
  ),
  textOutput("selected")
)

server <- function(input, output, session) {
  observe({
    updateCheckboxGroupInput(
      session, 'checka', choices = df$state[1:13],
      selected = if (input$all_none == TRUE) df$state
    )
  })
  observe({
    updateCheckboxGroupInput(
      session, 'checkb', choices = df$state[14:25],
      selected = if (input$all_none == TRUE) df$state
    )
  })
  
  output$selected <- renderText({
    all_selected <- paste(c(input$checka, input$checkb), collapse = ", ")
  })
}

shinyApp(ui, server)

Upvotes: 1

Views: 578

Answers (2)

norie
norie

Reputation: 9857

You should move the code that selects/deselects all the states so that it runs when the All/None checkbox is clicked.

To stop that code running at startup, you can use the ignoreInit argument.

library(shiny)
library(tidyverse)

df <- tibble(
  state = c("Alabama", "Alaska", "Arizona", "Arkansas",
            "California", "Colorado", "Connecticut", "Delaware", "Florida",
            "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa",
            "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts",
            "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana",
            "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico",
            "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma",
            "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota",
            "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington",
            "West Virginia", "Wisconsin", "Wyoming")
)

selected_states <- c("Alabama", "Alaska","Minnesota")

ui <- fluidPage(
  
  wellPanel(
    checkboxInput('all_none', 'All/None'),
    tags$label("Choose :"),
    fluidRow(
      column(
        width = 4,
        checkboxGroupInput(
          selected = selected_states,
          inputId = "checka",
          label = NULL,
          choices = df$state[1:13]
        )
      ),
      
      column(
        width = 4,
        checkboxGroupInput(
          selected = selected_states,
          inputId = "checkb",
          label = NULL,
          choices = df$state[14:25]
        )
      )
    )
  ),
  textOutput("selected")
)

server <- function(input, output, session) {
  observeEvent(input$all_none,{
    updateCheckboxGroupInput(
      session, 'checka', choices = df$state[1:13],
      selected = if (input$all_none == TRUE) df$state
    ) 
    updateCheckboxGroupInput(
      session, 'checkb', choices = df$state[14:25],
      selected = if (input$all_none == TRUE) df$state
    )
  }, ignoreInit = 1)

  output$selected <- renderText({
    all_selected <- paste(c(input$checka, input$checkb), collapse = ", ")
  })
}

shinyApp(ui, server)

Upvotes: 1

robert_mi
robert_mi

Reputation: 84

I would probably replace the single All/None button with separate actionButtons for "Select All" and "Select None". The code could then look like this:

library(shiny)
library(shinyWidgets)
library(tidyverse)

df <- tibble(
  state = c("Alabama", "Alaska", "Arizona", "Arkansas",
            "California", "Colorado", "Connecticut", "Delaware", "Florida",
            "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa",
            "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts",
            "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana",
            "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico",
            "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma",
            "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota",
            "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington",
            "West Virginia", "Wisconsin", "Wyoming")
)

selected_states <- c("Alabama", "Alaska","Minnesota")

ui <- fluidPage(
  
  wellPanel(
    actionButton('selectall','Select All'),
    actionButton('selectnone','Select None'),
    br(),
    br(),
    tags$label("Choose :"),
    fluidRow(
      column(
        width = 4,
        checkboxGroupInput(
          selected = selected_states,
          inputId = "checka",
          label = NULL,
          choices = df$state[1:13]
        )
      ),
      
      column(
        width = 4,
        checkboxGroupInput(
          selected = selected_states,
          inputId = "checkb",
          label = NULL,
          choices = df$state[14:25]
        )
      )
    )
  ),
  textOutput("selected")
)

library(shiny)
?updateCheckboxGroupInput

server <- function(input, output, session) {
  
  observeEvent(
    input$selectall, {
      updateCheckboxGroupInput(
        session, 'checka',
        choices = df$state[1:13],
        selected = df$state)
    }
  )
  observeEvent(
    input$selectall, {
      updateCheckboxGroupInput(
        session, 'checkb',
        choices = df$state[14:25],
        selected = df$state)
    }
  )

  observeEvent(
    input$selectnone, {
      updateCheckboxGroupInput(
        session, 'checka',
        choices = df$state[1:13],
        selected = character(0))
    }
  )
  observeEvent(
    input$selectnone, {
      updateCheckboxGroupInput(
        session, 'checkb',
        choices = df$state[14:25],
        selected = character(0))
    }
  )
  
  output$selected <- renderText({
    all_selected <- paste(c(input$checka, input$checkb), collapse = ", ")
  })
}

shinyApp(ui, server)

Incidentally, if you'd like all 25 states to appear in a single selector, but formatted as two columns, you could use the CSS property column-count applied to the checkboxGroupInput - this would allow you to use a single selector, thereby simplifying the code but resulting in the same appearance:

library(shiny)
library(shinyWidgets)
library(tidyverse)

df <- tibble(
  state = c("Alabama", "Alaska", "Arizona", "Arkansas",
            "California", "Colorado", "Connecticut", "Delaware", "Florida",
            "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa",
            "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts",
            "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana",
            "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico",
            "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma",
            "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota",
            "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington",
            "West Virginia", "Wisconsin", "Wyoming")
)

selected_states <- c("Alabama", "Alaska","Minnesota")

ui <- fluidPage(
  tags$head(
      tags$style(HTML("
      div .shiny-options-group {
        column-count: 2;
      }
      "))
  ),
  
  wellPanel(
    actionButton('selectall','Select All'),
    actionButton('selectnone','Select None'),
    br(),
    br(),
    tags$label("Choose :"),
    fluidRow(
      column(
        width = 8,
        checkboxGroupInput(
          selected = selected_states,
          inputId = "checka",
          label = NULL,
          choices = df$state[1:25]
        )
      )
      )
  ),
  textOutput("selected")
)

library(shiny)
?updateCheckboxGroupInput

server <- function(input, output, session) {
  
  observeEvent(
    input$selectall, {
      updateCheckboxGroupInput(
        session, 'checka',
        choices = df$state[1:25],
        selected = df$state)
    }
  )

  observeEvent(
    input$selectnone, {
      updateCheckboxGroupInput(
        session, 'checka',
        choices = df$state[1:25],
        selected = character(0))
    }
  )

  output$selected <- renderText({
    all_selected <- paste(c(input$checka, input$checkb), collapse = ", ")
  })
}

shinyApp(ui, server)

Upvotes: 1

Related Questions