Search code examples
rshinyshiny-reactivity

Shiny: Update a reactive value with textInput() in modalDialog()


I Want to update a Value based on a textInput() within an modalDialog(). I found this answer which does work, but it uses reactiveValues() which creates problems in my case further down in my code.

Is there a way to to update my value text through textInput() and modalDialog() without the use of reactiveValues()?

This works

library(shiny)
library(shinyWidgets)

if (interactive()) {
  shinyApp(
    ui <- fluidPage(
      actionBttn("reset", "RESET", style="simple", size="sm", color = "warning"),
      verbatimTextOutput(outputId = "text")
    ),
    server = function(input, output, session) {
      l <- reactiveValues()
      observeEvent(input$reset, {
        # display a modal dialog with a header, textinput and action buttons
        showModal(modalDialog(
          tags$h2('Please enter your personal information'),
          textInput('name', 'Name'),
          textInput('state', 'State'),
          footer=tagList(
            actionButton('submit', 'Submit'),
            modalButton('cancel')
          )
        ))
      })

      # only store the information if the user clicks submit
      observeEvent(input$submit, {
        removeModal()
        l$name <- input$name
        l$state <- input$state
      })

      # display whatever is listed in l
      output$text <- renderPrint({
        if (is.null(l$name)) return(NULL)
        paste('Name:', l$name, 'and state:', l$state)
      })
    }
  )
}

This does not work

It fails to update the value l when I dont use the l <- reactiveValues().

library(shiny)
library(shinyWidgets)

if (interactive()) {
  shinyApp(
    ui <- fluidPage(
      actionBttn("reset", "RESET", style="simple", size="sm", color = "warning"),
      verbatimTextOutput(outputId = "text")
    ),
    server = function(input, output, session) {
      
      l <- NULL
      
      
      
      observeEvent(input$reset, {
        # display a modal dialog with a header, textinput and action buttons
        showModal(modalDialog(
          tags$h2('Please enter your personal information'),
          textInput('name', 'Name'),
          footer=tagList(
            actionButton('submit', 'Submit'),
            modalButton('cancel')
          )
        ))
      })
      
      # only store the information if the user clicks submit
      observeEvent(input$submit, {
        removeModal()
        l <- input$name
      })
      
      # display whatever is listed in l
      output$text <- renderPrint({
        if (is.null(l)) return(NULL)
        paste('Name:', l)
      })
    }
  )
}

Solution

  • renderPrint needs a reactive dependency to be invalidated and re-rendered. Accordingly using a non-reactive variable in this scenario isn't making any sense.

    You should rather work on the downstream problems.

    Here is another approach using eventReactive:

    library(shiny)
    library(shinyWidgets)
    
    ui <- fluidPage(
      br(),
      actionBttn("reset", "RESET", style="simple", size="sm", color = "warning"),
      verbatimTextOutput(outputId = "text")
    )
    
    server <- function(input, output, session) {
      observeEvent(input$reset, {
        # display a modal dialog with a header, textinput and action buttons
        showModal(modalDialog(
          tags$h2('Please enter your personal information'),
          textInput('name', 'Name'),
          footer=tagList(
            actionButton('submit', 'Submit'),
            modalButton('cancel')
          )
        ))
      })
      
      # only store the information if the user clicks submit
      submittedName <- eventReactive(input$submit, {
        removeModal()
        input$name
      })
      
      output$text <- renderPrint({
        req(submittedName())
        paste('Name:', submittedName())
      })
    }
    
    shinyApp(ui, server)
    

    Edit: using reactiveVal for the placeholder:

    library(shiny)
    library(shinyWidgets)
    
    ui <- fluidPage(
      br(),
      actionBttn("reset", "RESET", style="simple", size="sm", color = "warning"),
      verbatimTextOutput(outputId = "text")
    )
    
    server <- function(input, output, session) {
      observeEvent(input$reset, {
        # display a modal dialog with a header, textinput and action buttons
        showModal(modalDialog(
          tags$h2('Please enter your personal information'),
          textInput('name', 'Name'),
          footer=tagList(
            actionButton('submit', 'Submit'),
            modalButton('cancel')
          )
        ))
      })
      
      submittedName <- reactiveVal("placeholder")
      
      # only store the information if the user clicks submit
      observeEvent(input$submit, {
        removeModal()
        submittedName(input$name)
      })
      
      output$text <- renderPrint({
        paste('Name:', submittedName())
      })
    }
    
    shinyApp(ui, server)