Reputation: 101
I am making a shiny app where the user needs to select dropdown options in a table. I am using rhandsontable, however it seems like I am only able to have one set of dropdown options for a single column. So row 1 has the same options as row 800. I want row 1 to have a different set of dropdown option than row 800.
Is there a way to do this?
I've thought about creating separate tables and pushing them together to look like one table. Only the first table would have column headers, and all other tables below it would not have column headers. I am trying to avoid this because rhandsontables have horizontal and vertical scroll bars, and there wouldn't be a way to sync the scroll bars between multiple tables. That would make the "one table" look a bit off. Actually having all the data in a single table would look and function much better.
I have a super simple example below:
require(shiny)
require(rhandsontable)
ui <- fluidPage(
hr(""),
# Display table
mainPanel(rHandsontableOutput("ExampleTable"))
)
server <- function(input, output) {
output$ExampleTable <- renderRHandsontable({
# creating table that will be displayed
df <- data.frame(Object = c("car", "car", "car", "house", "house", "house"), Needs = NA, stringsAsFactors = FALSE)
# defining dropdown options
dropdownOptions <- c("tires", "wipers", "headlights", "gutters", "carpet")
rhandsontable(df, rowHeaders = NULL, stretchH = "all") %>%
hot_col("Object", readOnly = TRUE) %>%
hot_col("Needs", type = "dropdown", source = dropdownOptions)
})
}
# Run the application
shinyApp(ui = ui, server = server)
I would like the dropdown options to only include "tires", "wipers", and "headlights" for all rows where the Object column has a value of "car". Because cars can never need gutters or carpet, I don't want the user to have the ability to select either of those options.
For each row where "house" is the value in the Object column, the user should only have two options displayed in the dropdown..."gutters" and "carpet". This will help avoid user error.
Upvotes: 8
Views: 2811
Reputation: 33417
Here is a working solution based on my example I shared here (and @Ben mentioned above):
library(shiny)
library(rhandsontable)
ui <- fluidPage(
hr(),
# Display table
mainPanel(rHandsontableOutput("ExampleTable"))
)
server <- function(input, output) {
# creating table that will be displayed
DF <- reactiveVal(data.frame(Object = c("car", "car", "car", "house", "house", "house"), Needs = NA_character_, stringsAsFactors = FALSE))
# update df() on user changes
observeEvent(input$ExampleTable, {
DF(hot_to_r(input$ExampleTable))
})
output$ExampleTable <- renderRHandsontable({
# defining dropdown options
carOptions <- c(NA_character_, "tires", "wipers", "headlights")
houseOptions <- c(NA_character_, "gutters", "carpet")
tmpExampleTable <- rhandsontable(DF(), rowHeaders = NULL, stretchH = "all", selectCallback = TRUE, width = 300, height = 300) %>%
hot_col("Object", readOnly = TRUE) %>%
hot_col("Needs", allowInvalid = FALSE, type = "dropdown", source = NA_character_, readOnly = TRUE)
if(!is.null(input$ExampleTable_select$select$r)){
selectedObject <- DF()[input$ExampleTable_select$select$r, "Object"]
if(selectedObject == "car"){
tmpExampleTable <- hot_col(tmpExampleTable, col = "Needs", allowInvalid = FALSE, type = "dropdown", source = carOptions) %>% hot_cell(row = input$ExampleTable_select$select$r, col = "Needs", readOnly = FALSE)
}
if(selectedObject == "house"){
tmpExampleTable <- hot_col(tmpExampleTable, col = "Needs", allowInvalid = FALSE, type = "dropdown", source = houseOptions) %>% hot_cell(row = input$ExampleTable_select$select$r, col = "Needs", readOnly = FALSE)
}
}
tmpExampleTable
})
}
# Run the application
shinyApp(ui = ui, server = server)
Edit: Here you can find a generalized approach for dependent rhandsontable dropdowns.
Upvotes: 9