rshinyr6

Why is the default value from an R6 object not displayed in a Shiny app when it is launched?


I am learning to use R6 in a Shiny app with the aim of separating the logic from the app.

I have a question about the value of the initialize function in the R6 class.

As shown in the reproducible example below, I have defined name = 'Eric' and set up the initialize function to assign ‘Eric’ as the default value of name. Why is ‘Eric’ not displayed when the app is launched?

enter image description here

library(shiny)
library(R6)
library(gargoyle)

# R6 object -----------------------------------------------------------------------------

ExampleR6 <- R6Class(
  classname = "example", 
  public    = list(
    name       = "Eric",
    initialize = \(name = "Eric") {
      self$name <- name
    }
  ))


# Module 1 ------------------------------------------------------------------------------

mod_1_UI <- function(id) {
  ns <- NS(id)
  tagList(
    textInput(inputId = ns("input_name"), label = "What's your name?")
  )
}

mod_1_Server <- function(id, r6) {
  moduleServer(
    id,
    function(input, output, session) {
      
      observeEvent(input$input_name, {
        
        r6$name <- input$input_name
        
        trigger("change_name")
      })
    }
  )
}


# Module 2 ------------------------------------------------------------------------------

mod_2_UI <- function(id) {
  ns <- NS(id)
  tagList(
    textOutput(outputId = ns("output_name"))
  )
}

mod_2_Server <- function(id, r6) {
  moduleServer(
    id,
    function(input, output, session) {
      
      observeEvent(watch("change_name"), {
        
        output$output_name <- renderText(r6$name)
      })
    }
  )
}


# Main app ------------------------------------------------------------------------------


ui <- fluidPage(
  
  mod_1_UI(id = "mod_1"),
  mod_2_UI(id = "mod_2")
)

server <- function(input, output, session) {
  
  hello_r6 <- ExampleR6$new()
  
 init("change_name")
  
  mod_1_Server(id = "mod_1", r6 = hello_r6)
  mod_2_Server(id = "mod_2", r6 = hello_r6)
}

shinyApp(ui, server)

Solution

  • There is a lot more going on in your MRE than just using R6. I'm not sure what you're trying with the initialize = part - setting name = "Eric" is sufficient and you can tell that by printing hello_r6$name in the main server. The reason your MRE doesn't work is that you are overwriting the initial value in mod1 with r6$name <- input$input_name . If you wrap that like this it will work as expected:

     if (input$input_name != ""){
       r6$name <- input$input_name
     }
    

    Putting output inside observeEvent is not best practice. This is a better alternative to achieve the same result with {gargoyle}:

    output$output_name <- renderText({
                            watch("change_name")
                            r6$name
                           })