简体   繁体   English

uiOutput 忽略<head>要么<script> tag

[英]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.我正在尝试通过 Outdooractive 的 API 在我的 Shiny 应用程序中包含一个 Outdooractive(.com) 地图,该应用程序使用一个 html 页面,在标题中带有一个脚本标签,在正文中使用一个 JavaScript 标签。

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.使用 Outdooractive 的 html 模板,将其保存为 html 文件,然后通过includeHTML("originalFile.html")将其包含在 Shiny App 中时,地图显示正确。 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 .但是,由于我希望地图的坐标是交互式的(不将其保存到中间的文件中),我尝试使用闪亮的标签在renderUI创建 html,并通过uiOutput显示它。 When doing so, the JavaScript part does not seem to be processed at all.这样做时,JavaScript 部分似乎根本没有被处理。 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 .有趣的是,当我用tags$header替换标签tags$headtags$header发生同样的情况。

Here is my app.R :这是我的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):要完全复制该示例,这将是originalFile.html (当app.R第 23 app.R未注释时有效):

<!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:我宁愿在观察者中调用一些JavaScript

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. shinyjs的使用使得在R使用JavaScript变得shinyjs You need to call useShinyjs somewhere in your UI and then you can issue arbitrary JS code via runjs .您需要在UI某处调用useShinyjs ,然后您可以通过runjs发出任意JS代码。
  • 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.我使用观察者,每当lat和/或lng更改并移动静态部分(即 API 和css到 UI 的加载)时,它都会调用相应的JS函数。
  • Important Note.重要的提示。 Initially, I used the following snippet in my UI instead of includeHTML :最初,我在UI使用了以下代码段而不是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.但是,这无法从outdooractive 加载JS ,我收到响应代码403 (禁止),即outdoor 拒绝了我的请求。 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`):无论出于什么有趣的原因,在 html 文件中硬编码该位并使用includeHTML似乎都有效(我再次可以简单猜测,但我假设 Outdooractive 尝试以某种方式确定您是在本地使用还是已经在生产中使用测试帐户。也许tags$script部分未通过此测试,而静态方法通过此测试,但这只是我的纯猜测 - 更重要的是includeHTML解决方法有效。但是您应该尝试用自己的键替换键,看看您是否仍然需要includeHTML部分,或者您可以直接tags$script in your UI 中使用tags$script in your script`):
<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:我添加了该应用在 Chrome 中的外观的 gif:

应用程序 Gif

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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