ebailey78 / shinyBS

Twitter Bootstrap Components for Shiny
182 stars 47 forks source link

bsCollapse with list of child elements throws an error #91

Open nFrechen opened 6 years ago

nFrechen commented 6 years ago

I trie to generate a bunch of collapsePanels with an apply function. This works for a lot of shiny elements like inputs, tabPanels etc. The bsCollapse function however shows an error when given a list of child elements.

Tor reproduce the error use the following app:

library(shiny)
library(shinyBS)
server <- function(input, output) {}

ui <- fluidPage(
  lapply(1:3, function(x) textInput(x, paste("Select", x))), # works

  bsCollapse(
    lapply(1:3, function(x) bsCollapsePanel(paste("Collapse", x))) # doesn't work
   )
)

shinyApp(ui = ui, server = server)

I get this error:

Warning: Error in if: argument is of length zero
Stack trace (innermost first):
    48: bsCollapse
    47: tag
    46: tags$div
    45: div
    44: tagList
    43: attachDependencies
    42: bootstrapPage
    41: fluidPage
     1: runApp
Error : argument is of length zero

I use the package version 0.61 on R version 3.3.3. I tried the latest version from github and it produced similar errors.

Please let me know if you need further details.

Thank you very much!

benjaminrobinson commented 6 years ago

If you just remove the bsCollapse in there, this code works! I'm still learning my way around the package and I ran into that issue earlier today and removing the bsCollapse did the trick. Not totally sure why!

library(shiny)
library(shinyBS)
server <- function(input, output) {}

ui <- fluidPage(
  lapply(1:3, function(x) textInput(x, paste("Select", x))),
  lapply(1:3, function(x) bsCollapsePanel(paste("Collapse", x)))
)

shinyApp(ui = ui, server = server)
chrismiddleton commented 5 years ago

@nFrechen @benjaminrobinson This is probably no longer relevant since it was quite a while ago, but since I've made the same mistake before, I thought I should comment with the solution.

The bsCollapse function expects a variable number of arguments, rather than a single-argument list. To call such a function with a dynamic number of children, you can use do.call like so:

do.call(bsCollapse, lapply(1:3, function(x) bsCollapsePanel(paste("Collapse", x))))

This will take your list and pass it to bsCollapse as a variable number of arguments.

earnaud commented 3 years ago

Hi,

I use shinyBS::bsCollapse*() (great tool, thanks you). But: this seems to be an unstable behavior. For instance, the attached code follows your recommendation but ends up with the same bug.

library(shiny)

ui <- fluidPage(
  shinyjs::useShinyjs(),
  uiOutput("edit_files")
)

server <- function(input, output, session) {
  output$edit_files <- renderUI({
    files <- dir("~/Documents/Test data/EAL samples/", full.names = TRUE)
    tables <- setNames(
      lapply(files, data.table::fread, data.table = FALSE, stringsAsFactors = FALSE),
      basename(files)
    )

    do.call(
      tabsetPanel,
      args = c(
        id = session$ns("tabset"),
        lapply(
          basename(files),
          tables = tables,
          # file UI - tab content
          function(table.name, tables) {
            table <- tables[[table.name]]
            browser()
            tabPanel(
              title = table.name,
              value = table.name,

              do.call(
                shinyBS::bsCollapse,
                args = c(
                  id = session$ns(table.name),
                  multiple = FALSE,
                  lapply(
                    seq(nrow(table)),
                    id = session$ns(table.name),
                    table.name = table.name,
                    table = table,
                    # row UI - collapsePanel
                    function(test, id, table.name, table) {
                      # Rest of the UI
                    }
                  )
                )
              )
            )
          }
        )
      )
    )
  })
}

shinyApp(ui, server)