简体   繁体   中英

R Shiny, how to update variable within observeEvent call

I am unable to update a list within an observeEvent call.

The list is called Participants and is a list-of-lists - ie a profile for each user. Participants is supposed to be updated by any user on a certain observeEvent call.

I have tried making the variable reactive and also non-reactive, but it does not work.

Below is a minimum working example

ui.R

The code for user

library(shiny)

shinyUI( fluidPage(
    sidebarLayout(
        #---------------------------------------------------
        # accept user transid
        sidebarPanel(
            numericInput("transid", "Transid", 0), 
            actionButton("accept", "Accept" )
        ),
        #---------------------------------------------------
        # Return user spreadsheet
        mainPanel( verbatimTextOutput("userSpreadSheet"))
))
)

server.R

The code for server #--------------------------------------------------- ################## # Definitions library(shiny)

## Create Participant List
ParticipantsDF <- data.frame(
    Name=stringi::stri_rand_strings(n=20, length=8, pattern="[a-z]"),
    ID=paste0("JA",1:20) ) 
spreadsheet  <- list(data.frame(foo=1:10, bar=runif(10), transid=NA) )
Participants <- apply( ParticipantsDF, 1, function(e){
     c( as.list(e), spreadsheet=spreadsheet ) })
ParticipantIDs <- ParticipantsDF$ID
ParticipantNames <- ParticipantsDF$Name

## Update Participants by changing a person
## based on user input of transid value
    ## change persons sublist named ``transid''
update_person <- function(transid, pid, participants){
    ## Which User
    userProfile_u <- participants[[pid]]
    ## Update User next transid to TRUE
    rows_vacant <- is.na(userProfile_u$spreadsheet$transid)
    row_update <- head( which(rows_vacant),1)
    userProfile_u$spreadsheet[row_update, "transid"] <- TRUE 
    ## Update Participants
    participants[[pid]] <- userProfile_u
    Participants <<- participants
}

#----------------------------------------------------------------------
##################
# Server 
server <- function( input, output, session){

    #---------------------------------------------------
    # Get authorized user: requires shiny-server-pro
    user <- session$user

    #---------------------------------------------------
    # Return user profile
    userPID <- which(ParticipantIDs == session$user )
    userProfile <- Participants[[userPID]]
    #---------------------------------------------------
    # When user clicks ``accept'', update Participants
    observeEvent(input$accept, {
        update_person(
            input$transid,
            userPID,
            Participants
        )
    })
    #---------------------------------------------------
    # Display spreadsheet to user
    ## Does Not Update!
    output$userSpreadSheet <- renderPrint({
        Participants[[userPID]][["spreadsheet"]] })
    ## Updates (Based on Accepted Answer)
    #ReactiveParticipants <- reactiveValues(Participants=Participants)
    #output$userSpreadSheet <- renderPrint({
    #    ReactiveParticipants$Participants[[userPID]][["spreadsheet"]]
    #})
    #observe({  invalidateLater(100)
    #    ReactiveParticipants$Participants <<- Participants
    #})
}
shinyServer(server)

If I edit the above code not to use renderPrint reactiveValues, then it still does not work.

It looks that there might be some issues with reactivity. As far as I know, session$user will not change during the application runtime (for that user) so the reactive statement and its dependencies might not execute the second time at all (that would be why the last piece does not update).

The second part I am not sure is how isolate can work on Participants as this is a static variable in global environment, not a reactive object. Can you perhaps provide a fully reproducible piece of code?


Edit: Your example is actually very close, the main problem is that you are trying to read static global variable in an observer ( renderPrint ). As your function update_person also returns Participants while saving them to the global environment, you can use it directly as a reactiveValue and then call it:

server <- function(input, output, session){
  #---------------------------------------------------
  # Get authorized user: requires shiny-server-pro
  user <- session$user

  #---------------------------------------------------
  # Return user profile
  userPID <- which(ParticipantIDs == user )
  userProfile <- Participants[[userPID]]

  rv <- reactiveValues(Participants = Participants)

  observeEvent(input$accept, {
     rv$Participants <- update_person(
       input$transid,
       userPID,
       Participants
     )
  })

  output$userSpreadSheet <- renderPrint({
    rv$Participants[[userPID]][["spreadsheet"]]
  })
}

I hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM