Call a shiny module a dynamic number of times using a for loop

Viewed 171

I've created a shiny module that display as much textInputs as the length of another variable on a row.

If I call these module one after the other manually, it works just fine:

library(shiny)
library(shinydashboard)

scenarios <- c("Scenario 1", "Scenario 2", "Scenario 3", "Scenario 4")

scenarioInput <- function(id, nomScenario){
  ns <- NS(id)
  textInput(inputId = ns("scenario"), label=nomScenario)
}

box1 <- shinydashboard::box(width=NULL, status="primary", align="center",
            HTML("<h1><strong>Scénarios</strong></h1>"), 
            splitLayout(
              cellWidths = rep(paste0(100/length(scenarios), "%"), length(scenarios)),   
              cellArgs = list(style = "padding: 2%"),
              scenarioInput(id=1, nomScenario=scenarios[1]),
              scenarioInput(id=2, nomScenario=scenarios[2]),
              scenarioInput(id=3, nomScenario=scenarios[3]),
              scenarioInput(id=4, nomScenario=scenarios[4])
            )
)

body <- dashboardBody(
  fluidRow(
    column(width = 12,
           box1,
    )
  )
)


ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  body
)

shinyApp(ui = ui, server = function(input, output) { })

However, if I try to call these modules through a for loop, no textInput boxes is displayed to my screen.

box1 <- shinydashboard::box(width=NULL, status="primary", align="center",
            HTML("<h1><strong>Scénarios</strong></h1>"), 
            splitLayout(
              cellWidths = rep(paste0(100/length(scenarios), "%"), length(scenarios)),   
              cellArgs = list(style = "padding: 2%"),
              for (i in 1:length(scenarios)){scenarioInput(id=i, nomScenario=scenarios[i])}
            )
)

Would anyone know a way to make this work?

1 Answers

You need to pass your textInputs as arguments to splitLayout. This can be done via do.call:

library(shiny)
library(shinydashboard)

scenarios <- c("Scenario 1", "Scenario 2", "Scenario 3", "Scenario 4")

scenarioInput <- function(id, nomScenario) {
  ns <- NS(id)
  textInput(inputId = ns("scenario"), label = nomScenario)
}

box1 <- shinydashboard::box(
  width = NULL,
  status = "primary",
  align = "center",
  HTML("<h1><strong>Scénarios</strong></h1>"),
  do.call(
    what = splitLayout,
    args = c(
      lapply(seq_along(scenarios), function(i) {
        scenarioInput(id = i, nomScenario = scenarios[i])
      }),
      list(cellWidths = list("10%", "20%", "30%", "40%")), # list(cellWidths = rep(paste0(100 / length(scenarios), "%"), length(scenarios))),
      list(cellArgs = list(style = "padding: 2%"))
    )
  )
)

body <- dashboardBody(fluidRow(column(width = 12, box1)))


ui <- dashboardPage(dashboardHeader(),
                    dashboardSidebar(),
                    body)

shinyApp(
  ui = ui,
  server = function(input, output) {  }
)

result

Related