0

I would like to update the content of a reactive object that is holding a tibble in response to a button push and I can't figure out the syntax. The solution that was posted here contains a solution that used to work but now it throws an error.

Below is a reprex of the issue I am having. Run the write.csv(iris, "text.csv") first.

library(shiny)
library(tidyverse)

# create the test data first
# write.csv(iris, "text.csv")

server <- shinyServer(function(input, output) {

    in_data <- reactive({
        inFile <- input$raw
        x <- read.csv(inFile$datapath, header=TRUE)
    })

    subset <- reactive({
        subset <- in_data() %>%
            filter(Species == "setosa")
    })

    observeEvent(input$pushme, {
            subset()$Sepal.Length[2] <- 2
    })

    output$theOutput <- renderTable({
        subset()
    })
})


ui <- shinyUI(
    fluidPage(
        fileInput('raw', 'Load test.csv'),
        actionButton("pushme","Push Me"),
        tableOutput('theOutput')     
    )
)
shinyApp(ui,server)

My code to change the value:

subset()$Sepal.Length[2] <- 2

Throws this error:

Error in <-: invalid (NULL) left side of assignment

What is the syntax for programmatically changing the value in a reactive tibble?

itsMeInMiami
  • 2,324
  • 1
  • 13
  • 34

1 Answers1

1

You can't modify directly the value of a reactive object. You have to define first a static object that will take the value of the reactive object, and then you can modify the value of the static object. Two options for you (no modifications in ui):

  • The first one is to use renderTable just after having subseted your data, and then to modify your table inside observeEvent:
server <- shinyServer(function(input, output) {

  in_data <- reactive({
    inFile <- input$raw
    x <- read.csv(inFile$datapath, header=TRUE)
  })

  test1 <- reactive({
    data <- in_data() %>%
      filter(Species == "setosa")
    data
  })

  output$theOutput <- renderTable({
    req(input$raw)
    test1()
  })

  observeEvent(input$pushme, {
    output$theOutput <- renderTable({
      req(input$raw)
      test1 <- test1()
      test1$Sepal.Length[2] <- 2
      test1
    })
  })

})
  • The second one is to define another dataset (test2 here) that will be computed with eventReactive only if the button is pushed. Then you have to define which of the two datasets you want to use in renderTable using conditions on their existence:
server <- shinyServer(function(input, output) {

  in_data <- reactive({
    inFile <- input$raw
    x <- read.csv(inFile$datapath, header=TRUE)
  })

  test1 <- reactive({
    data <- in_data() %>%
      filter(Species == "setosa")
    data
  })

  test2 <- eventReactive(input$pushme, {
      test1 <- test1()
      test1$Sepal.Length[2] <- 2
      test1
    }
  )

  output$theOutput <- renderTable({
    if (input$pushme) {
      test2()
    }
    else {
      req(input$raw)
      test1()
    }
  })

})

By the way, you shouldn't call datasets (reactive or not) like function names. In your example, you have called subset the reactive dataset you modify. This is not good since this dataset will be used as subset() (because it is reactive). It may be confusing both for you and for the execution of the code.

bretauv
  • 7,756
  • 2
  • 20
  • 57