Skip to content

Instantly share code, notes, and snippets.

@daattali daattali/app.R
Last active Sep 9, 2019

Embed
What would you like to do?
Basic form-submission shiny app used in "Persistent data storage in shiny apps" article http://deanattali.com/blog/shiny-persistent-data-storage/
library(shiny)
# Define the fields we want to save from the form
fields <- c("name", "used_shiny", "r_num_years")
# Save a response
# ---- This is one of the two functions we will change for every storage type ----
saveData <- function(data) {
data <- as.data.frame(t(data))
if (exists("responses")) {
responses <<- rbind(responses, data)
} else {
responses <<- data
}
}
# Load all previous responses
# ---- This is one of the two functions we will change for every storage type ----
loadData <- function() {
if (exists("responses")) {
responses
}
}
# Shiny app with 3 fields that the user can submit data for
shinyApp(
ui = fluidPage(
DT::dataTableOutput("responses", width = 300), tags$hr(),
textInput("name", "Name", ""),
checkboxInput("used_shiny", "I've built a Shiny app in R before", FALSE),
sliderInput("r_num_years", "Number of years using R", 0, 25, 2, ticks = FALSE),
actionButton("submit", "Submit")
),
server = function(input, output, session) {
# Whenever a field is filled, aggregate all form data
formData <- reactive({
data <- sapply(fields, function(x) input[[x]])
data
})
# When the Submit button is clicked, save the form data
observeEvent(input$submit, {
saveData(formData())
})
# Show the previous responses
# (update with current response when Submit is clicked)
output$responses <- DT::renderDataTable({
input$submit
loadData()
})
}
)
@hansthompson

This comment has been minimized.

Copy link

commented Jul 2, 2015

Sorry if I am the only one who doesn't know this but what is "<<-"?

@klittle314

This comment has been minimized.

Copy link

commented Sep 8, 2015

copied the script and attempted to run today (Windows 7, R V3.2.2, RStudio 0.99.473, shiny v 0.12.2 and shinyapps 0.3.63).

Error message:

shiny::runApp()

Listening on http://127.0.0.1:4135
Error in if (is.null(data) || ncol(data) == 0) { :
missing value where TRUE/FALSE needed

Since this conditional execution does not appear in the app.R script, it must be somewhere else, which I can't find...The error message suggests that the object data is missing so the condition can't be evaluated.with is.null(data) OR ncol(data)

SOLUTION: found that the object responses is the name of a function in the utils namespace. When I changed the object to "responses1" , the code executes....

So the problem seems to arise when the object data is assigned to responses which is a function object not a data object....

thanks for your blog directions, I will keep learning now!!

@RajaAsyraf

This comment has been minimized.

Copy link

commented Jan 11, 2017

Hi hansthompson,

For your question about "<<-" operation, using "<<-", you can define a global variable and assign to the reactive function.

Refer here: http://stackoverflow.com/questions/15327506/r-shiny-how-to-save-input-data-to-the-server-or-access-input-variables-globally

@etwatson

This comment has been minimized.

Copy link

commented Mar 11, 2017

Hi,

I've made a change, adding a dateInput() to the input, but the form data is not in date format. How can i specify that the field "date" is as.Date() in the "responses" table?

screen shot 2017-03-11 at 12 15 19 pm

@john-magrini

This comment has been minimized.

Copy link

commented Jun 17, 2017

Any solves for ewatson's issue above? I'd be interested because I am having the same issue. I've tried using cast num > char > date per a suggestion and that didn't work, I still was getting the numeric values of dataInputs.

@angelovangel

This comment has been minimized.

Copy link

commented Jun 26, 2017

@etwatson,
this is a datatable (DT), so check this out (I don't know your code so this is just a general structure):
DT::renderDataTable({ datatable() %>% formatDate("date", toDateString) })
Here the helper functions of DT are explained:
https://rstudio.github.io/DT/functions.html

@armenic

This comment has been minimized.

Copy link

commented Dec 2, 2018

I use exactly the same code as in the Gist and for some reason from the 3rd input the data table is lagging by one row. For example, if I submit d1 for a name it shows immediately, then d2 for a name which shows up immediately as well, but when I submit the 3rd value then it does not show up in the data table immediately and only sows up after I submit the 4th value. From now the table is lagging by one.
Do you have any clue why this is happening?

As an alternative I used reactiveVal() which nicely does the job and does not mess with .GlobalEnv

library(shiny)

# Define the fields we want to save from the form
fields <- c("name", "used_shiny", "r_num_years")

# Shiny app with fields that the user can submit data for
shinyApp(
    ui = fluidPage(
        tableOutput("res"), tags$hr(),
        textInput("name", "Name", ""),
        checkboxInput("used_shiny", "I've built a Shiny app in R before", FALSE),
        sliderInput("r_num_years", "Number of years using R",
                    0, 25, 2, ticks = FALSE),
        actionButton("submit", "Submit")
    ),
    server = function(input, output, session) {
        
        rv <- reactiveVal()
        
        # When the Submit button is clicked, save the form data
        observeEvent(input$submit, {
            
            df <- as.data.frame(
                t(sapply(fields, function(X) input[[X]]))
            )
            
            rv(rbind(rv(), df))
        })
        
        # Show the previous res
        # (update with current response when Submit is clicked)
        output$res <- renderTable({
            input$submit
            rv()
        })     
    }
)
@TahorSuiJuris

This comment has been minimized.

Copy link

commented May 3, 2019

Hello Dean,

Love your coding style, have been reviewing your "Basic Shiny app without data storage".

Q1. When I quit the RStudio session, the RESPONSE data remains in the OS RAM?

@Patrikios

This comment has been minimized.

Copy link

commented Jun 8, 2019

Hi Dean,
can you explain how the bubbling trigger of the submit button is listened to and caught in the code chunk of rendering responses?
Why does the input$submit appear in the renderDataTable part? I would rather see this as better suited case for another orberveEvent.

    output$responses <- DT::renderDataTable({
      input$submit #when this is not here, the app wont render responses, however the event listening is not explicitly defined at this point
      loadData()
}) 

Also the formData seems not to be executed when the inputs stay the same, is it because of lazy loading? I figure this by adding a print statement to the formData code:

    formData <- reactive({
      print("formData executed")
      data <- sapply(fields, function(x) input[[x]])
      data
    })

I think there a some internals hidden to my sight I would like to understand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.