3

I am making a shiny app where the user selects objects and data in selected objects sums to totals in a nested reactable table. I am using a reactible table, with DT tables nested inside (maybe not ideal, but in the real app I need some functionalities of the nested tables which I only know how to do with DT). Each time the user selects things, the underlying data creating the tables changes, but I want to be able to click and see those changes without re-rendering the entire table and collapsing the nests that the user had expanded. Is there a way to do this in Shiny?

I thought updateReactable might be the way, but I couldn't figure out how to make it work.

I made a dumb little example here, where the user selects locations in the kitchen that they will look for ingredients for a meal. The table shows how many ingredients of each type the user finds enough of for the recipe, then the expand button shows a table of individual ingredients. I want to be able to click the UI checkbox and not have the table completely reset each time.

Thanks,

library(shiny)
library(reactable)
library(DT)
library(tibble)
library(dplyr)


ingredients <- tribble(
    ~location,         ~ingredient,   ~type, ~quantity,
    "Cabinet 1" ,       "carrots", "produce",      2,
    "Cabinet 1" ,       "potatoes", "produce",     4,
    "Cabinet 1" ,       "pasta",   "dry goods",    2,
    "Cabinet 2" ,       "bouillon", "dry goods",   1,
    "Cabinet 2" ,       "spices",   "dry goods",   2,
    "Cabinet 2" ,       "pasta",    "dry goods",   1,
    "Refridgerator" ,   "chicken",   "meat",       1,
    "Refridgerator" ,   "celery",   "produce",    2,
    "Refridgerator" ,   "onion",   "produce",     2,
    "Refridgerator" ,   "carrots", "produce",      3,
    
)


recipe_needs <- 
    tribble(
        ~ingredient, ~type,  ~quantity_needed,
        "carrots",   "produce",  5,
        "potatoes",   "produce", 4,
        "pasta",      "dry goods", 4,
        "bouillon",   "dry goods", 1,
        "spices",     "dry goods", 5,
        "chicken",    "meat",  1,
        "celery",     "produce", 2,
        "onion",      "produce", 2,
    )

ui <- fluidPage(

    checkboxGroupInput("checkGroup", label = h3("Check location"), 
                       choices = unique(ingredients$location)),
    br(),br(),br(),
    reactableOutput("nested_table"),
)


server <- function(input, output) {

    # make dataframes 
    ingredients_totals <- reactiveValues(
        # all ingredients you found in your kitchen
        ingredients_found = ingredients %>% 
            distinct(ingredient,type) %>%
            arrange(type) %>%
            mutate(quantity_found = 0),
        # how many ingredients where you have all you need, by type
        sums_by_type =  recipe_needs %>% 
            mutate(value = 0) %>%
            mutate(success = case_when(value >= quantity_needed ~ 1,
                                       TRUE ~ 0)) %>%
            group_by(type) %>%
            summarize(success = paste0(sum(success), "/", n()))
    )
    


    observe( {
        
        # sum up the ingredients in the places you looked
       location_totals <-
            ingredients %>% 
           mutate(quantity_found = case_when(location %in% input$checkGroup ~ quantity,
                                             TRUE ~ 0)) %>%
            group_by(ingredient) %>%
            summarize(quantity_found = sum(quantity_found)) %>%
           arrange(ingredient)
       
       # add ingredients found in your locations to a totals df
       ingredients_totals$ingredients_found <- 
           arrange(ingredients_totals$ingredients_found,ingredient) %>%
           mutate(quantity_found = location_totals$quantity_found) %>%
           left_join(recipe_needs)
        
       # calculate how many ingredients you have enough of
       ingredients_totals$sums_by_type =  recipe_needs %>% 
           arrange(ingredient) %>%
           mutate(value = location_totals$quantity_found) %>%
           mutate(success = case_when(value >= quantity_needed ~ 1,
                                      TRUE ~ 0)) %>%
           group_by(type) %>%
           summarize(success = paste0(sum(success), "/", n()))
       
       
    })
    

    # make nested table
    output$nested_table <- 
        renderReactable(
            reactable(ingredients_totals$sums_by_type,
                      details = function(index) {
                          typesums <- filter(ingredients_totals$ingredients_found, 
                                             type == sort(unique(ingredients_totals$ingredients_found$type))[index]) %>% select(-type) 
                          tbl <- datatable(typesums,options = list(dom = 't'))
                      },
            ))
    
}

shinyApp(ui, server)
ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
Jake L
  • 987
  • 9
  • 21
  • If you want someone to help you, please post a working MRE. For example, this statement `summarize(success = paste0(sum(success), "/", n()))` is incorrect as `success` has not been defined to `sum` yet. – YBS Mar 07 '22 at 15:47
  • @YBS whoops, I changed a variable name at the last second and messed it up. Fixed the MRE now, thanks for pointing that out. – Jake L Mar 07 '22 at 18:02

0 Answers0