How to move functions from Shiny App to Global.R file?

Viewed 91

I'm working on a Shiny App that uses lengthy text explanations in the modalDialog functions. User clicks on an Action Button and the explanation pops up in a dialogue box. I'd like to move these long text functions out of the App file (containing UI and Server) into a separate Global.R file to clean up the code, make it more readable. Why does my below attempt not work? I'm sure the solution is simple. It's addressed in several other Stack Exchange posts but the solutions presented don't seem to work in this case.

Below is a MWE of where I am currently in creating a separate Global.R (both files are saved in the same directory):

App.R file (the function it's reaching out to in Global.R file is called "AbeLincoln"):

library(shiny)
source("./Global.R")

ui <- fluidPage(style = "margin-top:20px",
  fluidRow
    (column(12, 
          actionButton("explain1",
          strong("Gettyburg Address"),
          icon = icon("info-circle"),
          style="font-size:19px;
                 position:fixed")
     ) # closes column
  ), # closes fluid row
)  # fluid page

server <- function(input, output) {
  AbeLincoln(input$explain1)
} # closes server

shinyApp(ui = ui, server = server)

Global.R file containing the Observe Event that responds to the Action Button and all the text:

AbeLincoln <- function(x){

observeEvent(x, {  
    showModal(modalDialog(  
      
      title = "Background and text of the Gettysburg Address",
      
      tags$ul(
        
        tags$li("Gettysburg Address is a speech that Abraham Lincoln delivered at 
                 the dedication of the Soldiers' National Cemetery in Gettysburg, PA."), 
        tags$li("On the afternoon of November 19, 1863."),
        tags$li("Four and a half months after the Union armies defeated those of the 
                 Confederacy at the Battle of Gettysburg."),
        tags$li("It is one of the best-known speeches in American history.")),
      
      tags$p(strong("Text of speech:")),
      
        "Four score and seven years ago our fathers brought forth upon this continent, 
        a new nation, conceived in Liberty, and dedicated to the proposition that all men 
        are created equal.",tags$p(""),
        "Now we are engaged in a great civil war, testing whether that nation, or any 
        nation so conceived and so dedicated, can long endure. We are met on a great 
        battle-field of that war. We have come to dedicate a portion of that field, as 
        a final resting place for those who here gave their lives that that nation might 
        live. It is altogether fitting and proper that we should do this.",tags$p(""),
      
        "",tags$p(""),
      
        "But, in a larger sense, we can not dedicate—we can not consecrate—we can not 
        hallow—this ground. The brave men, living and dead, who struggled here, have 
        consecrated it, far above our poor power to add or detract. The world will little 
        note, nor long remember what we say here, but it can never forget what they did here. 
        It is for us the living, rather, to be dedicated here to the unfinished work which 
        they who fought here have thus far so nobly advanced. It is rather for us to be here 
        dedicated to the great task remaining before us—that from these honored dead we take 
        increased devotion to that cause for which they gave the last full measure of devotion
        — that we here highly resolve that these dead shall not have died in vain—that this 
        nation, under God, shall have a new birth of freedom—and that government of the 
        people, by the people, for the people, shall not perish from the earth."
      
      ) # close modal dialog
    ) # close show modal 
  }) # close observe event
} # close function

Here is how the App is supposed to work. I present images below instead of posting the combined code above without Global.R.

First prompted with action button:

enter image description here

After clicking the action button this is what you get:

enter image description here

1 Answers

The observeEvent function assumes you are passing in an unquoted value. It's trying to observe x and not input$explain1. To make it more general, you should pass in the input to your function.

Change your wrapper to something like

AbeLincoln <- function(input, value){
  observeEvent(input[[value]], {  
    showModal(modalDialog(  ...) )
  }
}

and then your server would be

server <- function(input, output) {
  AbeLincoln(input, "explain1")
}

Alternatively you could mess with the observeEvent parameters and use non-standard evaluation on the AbeLincoln function. So you could do

AbeLincoln <- function(x){
  x <- substitute(x)
  observeEvent(x, 
    event.quoted=TRUE, event.env=parent.frame(), {  
    showModal(modalDialog(  ...) )
  }
}

or, alternatively,

AbeLincoln <- function(...) {
  observeEvent(..., event.env=parent.frame(), {  
    showModal(modalDialog(  ...) )
  }
}

And your server functions could still be

server <- function(input, output) {
  AbeLincoln(input$explain1)
}

It really just depends on what you find more intuitive I guess.

Related