user6147492
user6147492

Reputation:

Reactive content in RShiny app updates, but does not accumulate

I am attempting to output a table in my Shiny app that adds additional rows each time the "Submit" button is clicked. However, instead of accumulating rows, it just replaces the first one. The Shiny documentation didn't help me much (though it's really good).

Here's the UI:

shinyUI(fluidPage(

titlePanel("CSF Payroll App"),

sidebarLayout(
    sidebarPanel(
        textInput("name", "Put your name here"),
        textInput("job", "Job completed"),
        dateInput("date", "Input the date you worked"),
        numericInput("minutes", "Input the time you worked 
            (15 minute increments)", 0,0,240,15),
        submitButton("Submit")
    ),

    mainPanel(
        tableOutput("totalHours")
        )
)
))

Here's the server:

shinyServer(function(input, output) {

# Initialize a dataframe to hold all entries.
totalFrame <- data.frame(
    Name <- character(),
    Job <- character(),
    Date <- character(),
    Minutes <- numeric(), 
    stringsAsFactors=FALSE)
colnames(totalFrame) <- c("Name", "Job",
                          "Date", "Minutes")


# Create a temporary dataframe to take a new entry, reactively,
# then update the totalFrame with each new entry.
addNextEntry <- reactive({
    Name <- input$name
    Job <- input$job
    Date <- as.character(input$date)
    Minutes <- input$minutes
    tempFrame <- data.frame(Name, Job, Date, Minutes)
    totalFrame <- bind_rows(totalFrame, tempFrame)
    totalFrame
})

# Update the summary dataframe with new entries as they come in.
output$totalHours <- renderTable({
    addNextEntry()
})
})

How do I update the totalFrame in a way that takes reactive content, but accumulates in totalFrame rather than just replacing the first row again and again?

Sample Output: If I put ("Bob", "Cleans", 2017-04-25, 30) into the respective columns of the frame, it renders the table correctly, but then if I try to add another entry, it just replaces the Bob Cleans row.

Sample App Display

Upvotes: 0

Views: 205

Answers (1)

setempler
setempler

Reputation: 1751

Solution

Using

  • reactiveValues to generate a default and reactive table, combined with
  • observeEvent to check if your button is pressed, and
  • according to this post you need to change submitButton to actionButton.

This does update the initial table (as HubertL mentioned as problem).

Code

library(shiny)
library(dplyr)
ui <- shinyUI(fluidPage(

  titlePanel("CSF Payroll App"),

  sidebarLayout(
    sidebarPanel(
      textInput("name", "Put your name here"),
      textInput("job", "Job completed"),
      dateInput("date", "Input the date you worked"),
      numericInput("minutes", "Input the time you worked 
                   (15 minute increments)", 0,0,240,15),
      actionButton(inputId = 'button_1',label = 'Add')
      ),

    mainPanel(
      tableOutput("totalHours")
    )
  )
  ))

server <- function(input, output) {

  # default table
  totalFrame <- reactiveValues(table = data.frame(
      Name = character(),
      Job = character(),
      Date = character(),
      Minutes = numeric(), 
      stringsAsFactors = FALSE))


  # update default table, when actionButton is pressed
  observeEvent(input$button_1, {
    totalFrame$table <- bind_rows(
      totalFrame$table,
      data.frame(
        Name = input$name,
        Job = input$job,
        Date = as.character(input$date),
        Minutes = input$minutes
      )
    )
  })
  table <- reactive({totalFrame$table})

  # just render the table
  output$totalHours <- renderTable({
    table()
  })
}

shinyApp(ui = ui, server = server)

Output

before

enter image description here

after (pressing 5x)

enter image description here

Upvotes: 1

Related Questions