library(shiny)
library(R6)


ui <- list(
   textInput('line', 'Type a line here.'),
   actionButton('insert', 'OK'),
   p(strong('Your sentenses will be displayed below')),
   verbatimTextOutput('display')        
)


server1 <- function(input, output, session) {
    # This causes an error since 
    # reading output's values is prohibited.
    output$display <- renderText({ 
        ''
    })
    observeEvent(input$insert,
        { 
          output$display <- renderText({ 
              paste(output$display, input$line, sep='\n') 
          })
          updateTextInput(session, 'line', value='') 
        }
    )
}


server2 <- function(input, output, session) {
    # This does not behave as intended since
    # the change on D is not reflcted outside the 
    # expression of the observer
    
    D <- character(0)
    output$display <- renderText({ D })
    observeEvent(input$insert,
        { 
          D <- c(D, input$line)
          updateTextInput(session, 'line', value='') 
          output$display <- renderText({ paste(D, collapse='\n') })
        }
    )
}



# define a class for document container to keep the sentenses
Doc <- R6Class('document',
    public=list(
    text = character(0),
    initialize = function(init=character(0)) 
        { self$text <- init }
    )
)


server3 <- function(input, output, session) {
    # This works as desired.
    # The object D is floating during the operation,
    # and can be referred to from the expression.
    # So the values are updated from the expression
    # of the observer
    
    D <- Doc$new()  
    # keep the typed sentenses in this instance

    output$display <- renderText({ paste(D$text, collapse='\n') })
    observeEvent(input$insert,
        { 
          D$text <- c(D$text, input$line)
          updateTextInput(session, 'line', value='') 
          output$display <- renderText({ paste(D$text, collapse='\n') })
        }
    )
}


server4 <- function(input, output, session) {
    # This does not work since
    # shiny's reactive feature does not notice the update of D object.
    
    D <- Doc$new()  
    # keep the typed sentenses in this instance
    
    observeEvent(input$insert,
        { 
          D$text <- c(D$text, input$line)
          updateTextInput(session, 'line', value='') 
          print(D$text)  # the value of D do change
        }
    )
    
    # this is never called since changes are not noticed
    output$display <- renderText({ paste(D$text, collapse='\n') })
}



server5 <- function(input, output, session) {
    # This works since shiny now reacts to the update in insert button,
    # and hence the renderText is executed.
    # Yet, looks a bit ambiguous about the timing since
    # input$insert is related to two reactive expressions.
    
    D <- Doc$new()  
    # keep the typed sentenses in this instance
    
    observeEvent(input$insert,
        { 
          D$text <- c(D$text, input$line)
          updateTextInput(session, 'line', value='') 
        }
    )

    output$display <- renderText({ 
        input$insert
        paste(D$text, collapse='\n') 
    })
}



server6 <- function(input, output, session) {
    # V is an object observed by shiny
    # This approach seems the most shiny-ish
    V <- reactiveValues(text = character(0))

    observeEvent(input$insert,
        { 
          V$text <- c(V$text, input$line)
          updateTextInput(session, 'line', value='') 
        }
    )

    output$display <- renderText({
        paste(V$text, collapse='\n') 
    })
}

# pick the one you like
# runApp(list(ui=ui, server=server1))   # error
# runApp(list(ui=ui, server=server2))   # does not work
# runApp(list(ui=ui, server=server3))   # works
# runApp(list(ui=ui, server=server4))   # does not work
# runApp(list(ui=ui, server=server5))   # works
runApp(list(ui=ui, server=server6))   # works

