0

I am trying to create a Shiny app with a form that generate tabs and input (e.g., textInput, selectInput, etc.) based on the inputs stored in a dataframe. I created a simple example below that explains what I am trying to accomplish. Any ideas? I would like to use tidyverse but another approach will work.

# This is what I want
tabsetPanel(
  tabPanel("1",
           textInput("a", "a_lab"),
           textInput("b", "b_lab")),
  tabPanel("2",
           textInput("c", "c_lab"),
           textInput("d", "d_lab")),
  tabPanel("3",
           textInput("e", "e_lab"),
           textInput("f", "f_lab"))
)

# I have a dataframe that looks like this as my input
tab_str <- data.frame(
  tabnam=c(1,1,2,2,3,3),
  id=letters[1:6],
  lab=paste0(letters[1:6],"_lab")
)

# My function to make input controls are something like this
make_ctrl <- function(id, lab) textInput(id, lab)

# How can I obtain what I want--example at the top--using a "loop" approach;
# if possible using tidyverse; obviously what I have below is not working
tab_str %>% map(make_ctrl, id=tab_str$id)
rjss
  • 935
  • 10
  • 23
  • 1
    You will have to use `renderUI` on server side and `uiOutput` on ui side. – Roman Luštrik Oct 14 '17 at 06:59
  • 1
    See https://stackoverflow.com/questions/19130455/create-dynamic-number-of-input-elements-with-r-shiny – Roman Luštrik Oct 14 '17 at 07:50
  • Hi, modularization would be an answer (https://shiny.rstudio.com/articles/modules.html). The implementation would depend on if your data frame "tab_str" is dynamic or not. Does it change during the session by user's input, or is it defined just once and fixed? – Kota Mori Oct 14 '17 at 09:51
  • It is fixed throughout the sessiom; I was thinking to read the data.frame that have the input when the ShinyApp is loaded. I though the `renderUI` approach was more when you needed to change controls do to some user input. – rjss Oct 14 '17 at 16:53

1 Answers1

0

I'm not too familiar with tidyverse packages so here's a base R example, and let me know about the tidyverse equivalent.

The basic gist is:

  • map the input data to input controls
  • group the related controls into lists
  • for each group, construct a tabPanel from the list of child controls
  • construct a tabsetPanel from the list of tabPanels

This example uses:

  • apply to map over data.frame rows
  • tapply to group list elements
  • lapply to map over lists
  • do.call to pass args into a function using a list
inputs_by_tab <- tab_str %>%
  apply(1, function(row) textInput(row["id"], row["lab"])) %>%
  tapply(tab_str$tabnam, list)

tabs <- lapply(names(inputs_by_tab), function(name) {
  do.call(tabPanel, list(title = name, inputs_by_tab[[name]]))
})

tabset <- do.call(tabsetPanel, tabs)
greg L
  • 4,034
  • 1
  • 19
  • 18