简体   繁体   中英

uiOutput ignores <head> or <script> tag

I am trying to include an Outdooractive(.com) map in my Shiny app via Outdooractive's API, which uses an html page with a script tag in the header and a JavaScript tag in the body.

When using Outdooractive's html template, saving it as an html file and then including it in a Shiny App via includeHTML("originalFile.html") , the map is displayed correctly. However, since I want the coordinates for the map to be interactive (without saving it to file in-between), I tried to create the html in a renderUI using shiny tags, and display it via uiOutput . When doing so, the JavaScript part does not seem to be processed at all. The header above the map is shown, as is the text below it, but the map is ignored without error message. Interestingly, the same happens when I replace the tag tags$head by tags$header .

Here is my app.R :

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    titlePanel("Outdooractive Map"),

    # Sidebar with a text input for coordinates
    sidebarLayout(
        sidebarPanel(
            textInput ("lng",
                        "Longitude:",
                       value = "10.000",
                    ),
            textInput("lat",
                      "Latitude:",
                      value = "45.555")
        ),

        # Show the map 
        mainPanel(
            #includeHTML("originalFile.html") # This works
            textOutput("text"), # This shows the correct longitude/latitude
            uiOutput("map") # This seems to ignore the script
        )
    )
)

# Define server logic required to access API
server <- function(input, output) {
    
    output$map <- renderUI({
        lng = input$lng
        lat = input$lat
        
        tags$html(
            tags$div(
                tags$head(tags$title("Test"),
                          HTML('<meta charset="utf-8">'),
                          tags$script(
                              src = '//www.outdooractive.com/alpportal/oa_head.js?proj=api-dev-oa&amp;key=yourtest-outdoora-ctiveapi&amp;lang=en'
                          ),
                          tags$style(HTML(
                              '.oax .oax-cluster-marker-cont, .oax-cluster-marker-cont {background-color: red;}'
                          ))),
                tags$body(
                    h2("Outdooractive Routes"),
                    div(class = 'oax-top-cont'),
                    tags$script(HTML(paste(
                        'var conf = {frontendtype: "tour", zoom: 11, center:[ ', lng, ", ",  lat, ']}; var fvp = oa.api.flexviewpage( conf );')
                    )),
                    HTML('There should be a map on top of me.')
                )
            ),

        )
    })
    
    output$text <- renderText ({
        paste(input$lng, input$lat)
    })
}

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

To fully replicate the example, this would be the originalFile.html (which works when line 23 in app.R is uncommented):

<!DOCTYPE html>
<html>
  <head>
    <title>outdooractive platform - API Template</title>
    <meta charset="utf-8">

    
    <!-- load Outdooractive Javascript API -->
    <script type="text/javascript" 
            src="//www.outdooractive.com/alpportal/oa_head.js?proj=api-dev-oa&amp;key=yourtest-outdoora-ctiveapi&amp;lang=en"></script>


    <style>
      .oax .oax-cluster-marker-cont, .oax-cluster-marker-cont {
          background-color: red;
      }
    </style>

  </head>
  <body>
  <br>
  <br>
    <h2>Outdooractive Routes</h2>

    <!-- container used by FlexView API -->
    <div class="oax-top-cont"></div>


    <!-- and some lines of javascript inside a script tag -->
    <script type="text/javascript">

      var conf = {
          frontendtype:   "tour",          // choose content type
          zoom:           11,              // set initial zoom level
          center:       [ 10.292, 47.546 ] // set initial map center
      };
      
      var fvp = oa.api.flexviewpage( conf );

    </script>
  </body>
</html>

Any pointers would be much appreciated.

I would rather call some JavaScript in an observer:

library(shiny)
library(shinyjs)
library(glue)

# Define UI for application that draws a histogram
ui <- fluidPage(
   useShinyjs(),
   includeHTML("header.html"), ## see comment
   titlePanel("Outdooractive Map"),
   sidebarLayout(
      sidebarPanel(
         textInput ("lng",
                    "Longitude:",
                    value = "10.000",
         ),
         textInput("lat",
                   "Latitude:",
                   value = "45.555")
      ),
      mainPanel(
         div(
            class = "oax-top-cont"
         )
      )
   )
)

server <- function(input, output) {  
   observe({
      script <- glue("var conf = {{",
                     "frontendtype: 'tour',",
                     "zoom: 11,",
                     "center: [{input$lng}, {input$lat}]",
                     "}};",
                     "var fvp = oa.api.flexviewpage(conf);"
      )
      runjs(script)
   })
}

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

Some remarks:

  • The use of shinyjs makes using JavaScript in R a piece of cake. You need to call useShinyjs somewhere in your UI and then you can issue arbitrary JS code via runjs .
  • I use an observer, which calls the respective JS function whenever lat and/or lng change and moved the static part (ie the loading of the API and the css to the UI.
  • Important Note. Initially, I used the following snippet in my UI instead of includeHTML :
tags$head(
   tags$script(
      type = "text/javascript",
      src  = "//www.outdooractive.com/alpportal/oa_head.js?proj=api-dev-oa&amp;key=yourtest-outdoora-ctiveapi&amp;lang=en"
   ),
   tags$style(...)
)
  • However, this failed to load the JS from outdooractive and I got response code 403 (forbidden), ie outdoor denied my request. My guess is that this is due to using the test account. For whatever funny reason hardcoding that bit in a html file and using includeHTML seems to work (again I can simply guess, but I assume that outdooractive tries somehow to figure out whether you are using the test account just locally or already in production. And maybe the tags$script part fails this test, while the static approach passes this test, but this is just a pure guess from my side - more importantly includeHTML workaround works. But you should try to replace the keys by your own ones and see whether you still need the includeHTML part or you can directly use tags$script in your UI`):
<script type="text/javascript" 
        src="//www.outdooractive.com/alpportal/oa_head.js?proj=api-dev-oa&amp;key=yourtest-outdoora-ctiveapi&amp;lang=en">
</script>
<style>
   .oax .oax-cluster-marker-cont, .oax-cluster-marker-cont {
       background-color: red;
   }
</style>

Update

I add a gif of how the app look here in Chrome:

应用程序 Gif

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