Search code examples
rshinyhtml-inputshinyvalidate

shinyvalidate -warning message won't appear after inserting UI


I have a shiny app that dynamically removes and inserts input UI based on user selection. The UI generated by selectingchoice1 and choice2 share part of their input fields. I wanted to use the shinyvalidate package to add some validation rules that can apply to the shared inputs. In the following example, the user can make a selection on the sidebar. Once a choice is made, the div with ID "content" on the main panel will be deleted and a new div will be inserted. The rules seem to be working, but unless I type something in the input field first, the red warning message won't appear when I switch choices.

enter image description here

library(shiny)
library(glue)
library(shinyvalidate)

ui <- fluidPage(
  sidebarPanel(
  selectInput("select", label = "select", choices = c("", "choice1", "choice2"))
  ),
  mainPanel(id = "main",
            tags$div(id = "content"))
)


server <- function(input, output) {

  # validate input
  iv <- InputValidator$new()
  iv$add_rule("input", sv_required())
  iv$enable()

  
  
  observeEvent(input$select, {
  
    if(input$select == "choice1"){
      removeUI("#content")
      insertUI("#main", ui = tags$div(
        id = "content", 
        textInput("input", "input")))
    } 
    if(input$select == "choice2"){
      removeUI("#content")
      insertUI("#main", ui = tags$div(
        id = "content", 
        textInput("input", "input")))
    }

      })
  

}

# Run the application 
shinyApp(ui = ui, server = server)

Solution

  • This works by triggering iv$enable after the observeEvent has finished its work (is "invalidated" is the correct wording I think).

    server <- function(input, output) {
      
      # validate input
      iv <- InputValidator$new()
      iv$add_rule("input", sv_required())
      
      Validate <- reactiveVal(NULL)
      
      observeEvent(input$select, {
        
        iv$disable()
        
        if(input$select == "choice1"){
          removeUI("#content")
          insertUI("#main", ui = tags$div(
            id = "content", 
            textInput("input", "input")))
        } 
        if(input$select == "choice2"){
          removeUI("#content")
          insertUI("#main", ui = tags$div(
            id = "content", 
            textInput("input", "input")))
        }
        
        Validate(TRUE)
        
      })
      
      observeEvent(Validate(), {
        iv$enable()
        Validate(NULL)
      })
      
    }
    

    EDIT

    I don't know why, but you have to set immediate = TRUE in both removeUI and insertUI:

        if(input$select == "choice1"){
          removeUI("#content", immediate = TRUE)
          insertUI("#main", ui = tags$div(
            id = "content", 
            textInput("input", "input")), immediate = TRUE)
        } 
        if(input$select == "choice2"){
          removeUI("#content", immediate = TRUE)
          insertUI("#main", ui = tags$div(
            id = "content", 
            textInput("input", "input")), immediate = TRUE)
        }