Phil.He
Phil.He

Reputation: 154

Dynamically add columns to dataframe using Shiny input

I am trying to create the possibility for users to dynamically add new columns to a dataframe in a Shiny app whenever the action button is pressed.

I found a solution on how to dynamically add user input fields in Shiny on another stack overflow thread.

Now, I am trying to modify this code in order to dynamically add columns to a dataframe. My part of the code is commented out:

library(shiny)

ui <- shinyUI(fluidPage(
  
  sidebarPanel(
    
    actionButton("add_btn", "Add Textbox"),
    actionButton("rm_btn", "Remove Textbox"),
    textOutput("counter")
    # ,tableOutput("table")
    
  ),
  
  mainPanel(uiOutput("textbox_ui"))
  
))

server <- shinyServer(function(input, output, session) {
  
  # Track the number of input boxes to render
  counter <- reactiveValues(n = 0)
  
  # Track all user inputs
  AllInputs <- reactive({
    x <- reactiveValuesToList(input)
  })
  
  observeEvent(input$add_btn, {counter$n <- counter$n + 1})
  observeEvent(input$rm_btn, {
    if (counter$n > 0) counter$n <- counter$n - 1
  })
  
  output$counter <- renderPrint(print(counter$n))
  
  textboxes <- reactive({
    
    n <- counter$n
    
    if (n > 0) {
      isolate({
        lapply(seq_len(n), function(i) {
          textInput(inputId = paste0("textin", i),
                    label = paste0("Textbox", i), 
                    value = AllInputs()[[paste0("textin", i)]])
        })
      })
    }
    
  })
  
  # df <- reactive({
  #   n <- counter$n
  # 
  #   df <- data.frame(placeholder=NA)
  #   
  #   lapply(seq_len(n), function(i){
  #   df[[paste0("col", i)]] <- paste0("input$textin", i)
  #   }
  #   )
  #   df
  # })
  
output$textbox_ui <- renderUI({ textboxes() })
  
# output$table <- renderTable({
#   df()
#   
# })

  
})

shinyApp(ui, server)

Can someone help how to dynamically add a column to a dataframe whenever the actionButton ("add_btn") is pressed so that the input is filled into the new column. I found solutions that add rows, but I did not find any posts that help how to add columns.

Edit: Depending on the number of TextInputs, I want to create a number of columns with the information that was filled in textInput function. For example: If a user adds three textbooks with this information:

then I want the created dataftame to look like this:

df <- data.frame(Textbox1="A", Textbox2="B", Textbox3="C")

Upvotes: 0

Views: 940

Answers (1)

YBS
YBS

Reputation: 21287

Perhaps you are looking for this

library(shiny)
library(tidyr)
library(dplyr)

ui <- shinyUI(fluidPage(
  
  sidebarPanel(
    
    actionButton("add_btn", "Add Textbox"),
    actionButton("rm_btn", "Remove Textbox"),
    textOutput("counter")
    
  ),
  
  mainPanel(uiOutput("textbox_ui")
            ,tableOutput("table")
            )
  
))

server <- shinyServer(function(input, output, session) {
  
  # Track the number of input boxes to render
  counter <- reactiveValues(n = 0, df=NULL)
  
  # Track all user inputs
  AllInputs <- reactive({
    x <- reactiveValuesToList(input)
  })
  
  observeEvent(input$add_btn, {
    counter$n <- counter$n + 1
  })
  observeEvent(input$rm_btn, {
    
    if (counter$n > 0) counter$n <- counter$n - 1
    
  })
  
  output$counter <- renderPrint(print(counter$n))
  
  textboxes <- reactive({
    
    n <- counter$n
    
    if (n > 0) {
      isolate({
        lapply(seq_len(n), function(i) {
          textInput(inputId = paste0("textin", i),
                    label = paste0("Textbox", i), 
                    value = AllInputs()[[paste0("textin", i)]])
        })
      })
    }
    
  })
  
  output$textbox_ui <- renderUI({ textboxes() })
  
  df1 <- data.frame()
  
  observe({
    n <- counter$n
    if (n > 0) {
      df1 <- data.frame()
      
        lapply(1:n, function(i){
          req(input[[paste0("textin", i)]])
          
          df1 <<- rbind(df1,data.frame(input[[paste0("textin", i)]]))
          
        })
    }
    
    counter$df <- df1
  })
  
  output$table <- renderTable({
    if (is.null(counter$df)) return(NULL)
    else {
      n <- nrow(counter$df)
      if (n>0) {
        colnames(counter$df) <- "values"
        df1 <- counter$df %>% mutate(row=row_number())
        df1 %>% pivot_wider(names_prefix="Textbox", names_from = row, values_from = values)
      }else return(NULL)
    }
  })
  
  
})

shinyApp(ui, server)

Upvotes: 1

Related Questions