0

My goal with this shiny application is for people to be able to interactively match correct spellings of words to existing words. This is what I came up with so far which works and runs but it throws an error also. My question is, is there a better way to have the dropdown menu's formatted, how can I fix this error and also how can I then have the dataframe/table with users input saved after the fact.

Thanks!

The error:

Warning: Error in data.frame: arguments imply differing number of rows: 5, 0
  101: stop
  100: data.frame
   99: renderDataTable [#13]
   98: func
   85: renderFunc
   84: output$table
    3: runApp
    2: print.shiny.appobj
    1: <Anonymous>

The Code:



# Load Libraries
library(shiny)


words <- c("aapple", "apple", "bnanana", "pear", "banana")
choices = c("", "apple", "banana", "pear")

# Create User Interface
ui <- fluidPage(
  titlePanel("Matching Words with Dropdown Menus"),
  sidebarLayout(
    sidebarPanel(
      uiOutput("words_list"),
      hr(),
      uiOutput("dropdown_list")
    ), 
    mainPanel(
      h4("Results"),
      hr(),
      dataTableOutput("table")
    )
  )
)

# Create Server Function
server <- function(input, output) {
 
  # Output List of Dropdown Menus
  output$dropdown_list <- renderUI({
    lapply(words, function(x){
      selectInput(paste0("select_", x), x,
                  choices = choices)
    })
  })
  
  # Output Table of Results
  output$table <- renderDataTable({
    data.frame(word = words,
               type = sapply(words, function(x){
                 input[[paste0("select_", x)]]
               }))
  })

}

# Create Shiny App
shinyApp(ui = ui, server = server)
megmac
  • 547
  • 2
  • 11
  • 1
    Your `input` is empty on start, so `input[[paste0('select_', x)]]` yields nothing, which is where the mismatch comes from. https://stackoverflow.com/questions/26147558/what-does-the-error-arguments-imply-differing-number-of-rows-x-y-mean – Anonymous coward Dec 16 '22 at 21:32

1 Answers1

1

When you use input widgets in renderUI(), the input$id will be NULL when the app starts until uiOutout("dropdown_list") is sent to the browser. Therefore, you need to verify that the inputs are not NULL when the table is rendered.

library(shiny)

words <- c("aapple", "apple", "bnanana", "pear", "banana")
# replace "" with " " 
choices = c(" ", "apple", "banana", "pear")

ui <- fluidPage(
  titlePanel("Matching Words with Dropdown Menus"),
  sidebarLayout(
    sidebarPanel(
      uiOutput("words_list"),
      hr(),
      uiOutput("dropdown_list")
    ), 
    mainPanel(
      h4("Results"),
      hr(),
      dataTableOutput("table")
    )
  )
)

server <- function(input, output) {
  output$dropdown_list <- renderUI({
    lapply(words, function(x){
      selectInput(paste0("select_", x), x,
                  choices = choices)
    })
  })
  
  output$table <- renderDataTable({
    data.frame(word = words,
               type = sapply(words, function(x){
                 # check with req()
                 req(input[[paste0("select_", x)]])
               }))
  })
  
}

shinyApp(ui = ui, server = server)

My general approach is to never use input widgets inside renderUI() because of this; and only using renderUI() for "outputs". With that paradigm, you would create the ui-Part of the app by using lapply() inside fluidPage(). You can then use updateSelectInput() if you want to change the choices over time.

Gregor de Cillia
  • 7,397
  • 1
  • 26
  • 43
  • Do you know why after this application is closed, the rest of my R code does not continue to execute? – megmac Dec 20 '22 at 15:33