我目前正在try 在R中开发一个最小的CustomMessageHandling dashbord.我所做的只是将一条消息从R客户端发送到Javascript文件,然后在html文件中运行.错误如下:

jQuery.Deferred exception: Shiny is not defined ReferenceError: Shiny is not defined

在我的JavaScript文件中,该文件在我的中调用.html文件,我只需将其添加到文件底部,如下所示:

$(document).on('shiny:connected', function() {
  console.log("Hello, I am executing!");
  const clientID = "e800d12fc12c4d60960778b2bc4370af";
  var urlToBase64PDF;

  Shiny.addCustomMessageHandler('handler1', function()
    {
      doUpdate();
    }
    );

  function base64ToArrayBuffer(base64)
    {
    var bin = window.atob(base64);
    var len = bin.length;
    var uInt8Array = new Uint8Array(len);
    for (var i = 0; i < len; i++)
    {
      uInt8Array[i] = bin.charCodeAt(i);

    }
      return uInt8Array.buffer;
    }


  function doUpdate(message1)
    {
    urlToBase64PDF = message1;
    }


  document.write(urlToBase64PDF);
  console.log(urlToBase64PDF);

  document.addEventListener("adobe_dc_view_sdk.ready", function()
  {
    var adobeDCView = new AdobeDC.View({clientId: clientID, divId: "adobe-dc-view"});
    document.write(urlToBase64PDF);
    console.log(urlToBase64PDF);
    adobeDCView.previewFile({content:{ promise: Promise.resolve(base64ToArrayBuffer(urlToBase64PDF))}, metaData:{fileName: "check.pdf"}},
    {});
  });



});

在我的.html文件,我用以下方式调用它:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
    <meta id="viewport" name="viewport" content="width=device-width, initial-scale=1"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script type="text/javascript" src="index.js"></script>

</head>

其余功能内置于Shiny in R中,这是非常简单的UI和服务器部分:

app_ui <- function() {
  shiny::addResourcePath(
    'www', system.file('app/www', package = 'test')
  )

  tags$iframe(src="www/index.html", height = 600, width = 600)

最后是服务器部分:

app_server <- function(input, output, session){
  shinyjs::useShinyjs()
    message1 = "test"
    session$sendCustomMessage("handler1", message1)
  }

我已经try 了一切,到处搜索,甚至CustomMessageHandling的文档也以上述方式发送消息.然而,我仍然在控制台中看到了shiny 的未定义错误.

编辑:精确错误:

根本没有输出到控制台.

推荐答案

在embedded iframe中,不能使用父帧中的变量.这是出于安全原因.所以Shiny永远不会在iframe中定义,任何shiny事件都不能在iframe中收听.

您看到的是:

console.log("script starts")
$(document).on('shiny:connected', function() {
  console.log("oh yeah")
  // do some other things
});
console.log("script ends")
// index.js:1 script starts
// index.js:6 script ends

您可以看到中间部分从不运行,因为根本没有shiny:connected事件.当您收听未知事件时,遗憾的是它不会报告任何错误消息.

对此的更改使其更加清晰:

console.log("script starts")
$(function(){
    console.log(Shiny)
})
console.log("script ends")
index.js:1 script starts
index.js:5 script ends
jquery.min.js:2 jQuery.Deferred exception: Shiny is not defined ReferenceError: Shiny is not defined
    at HTMLDocument.<anonymous> (http://127.0.0.1:3168/www/index.js:3:17)
    at e (https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js:2:30005)
    at t (https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js:2:30307) undefined
jquery.min.js:2 Uncaught ReferenceError: Shiny is not defined
    at HTMLDocument.<anonymous> (index.js:3:17)
    at e (jquery.min.js:2:30005)
    at t (jquery.min.js:2:30307)

即使我们等待文档准备就绪,您也可以看到仍然没有Shiny个.

然后你会问jquery是从哪里来的.嗯,你是在index.html <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>秒的时候被引进的.这就是为什么你可以使用jquery,但不能使用Shiny.

Solution

一个简单的解决方案是使用服务器端渲染,因此它确保在初始化Shiny之后设置iframe.

library(shiny)

addResourcePath('www', "./")
ui <- fluidPage(
    uiOutput("iframe")
)

server <- function(input, output, session) {
    output$iframe <- renderUI({
        tags$iframe(src="www/index.html", height = 600, width = 600)
    })
}

shinyApp(ui, server)

这只解决了部分问题.我看到您有一个自定义处理程序,它根据Shiny控制的其他一些东西发出更新命令.在这种情况下,没有简单的解决方案,您需要cross-origin communication.

在下一个示例中,我使用一个按钮来模拟更新事件,它由shiny observeEvent控制.单击后,它将发送sendCustomMessage.在UI上,我们添加一些脚本来侦听此消息,然后将事件通过postMessage发送到iframe.

library(shiny)

addResourcePath('www', "./")
ui <- fluidPage(
    uiOutput("iframe"),
    actionButton("update", "update"),
    tags$script(HTML(
    "
    Shiny.addCustomMessageHandler('handler1', function(data){
        if(data.msg !== 'update') return ;
        $('#myiframe')[0].contentWindow.postMessage(data.msg, '*');
    });
    "
    ))
)

server <- function(input, output, session) {
    output$iframe <- renderUI({
        tags$iframe(id = "myiframe", src="www/index.html", height = 600, width = 600)
    })
    
    observeEvent(input$update, {
        session$sendCustomMessage("handler1", list(msg = "update"))
    }, ignoreInit = TRUE)
}

shinyApp(ui, server)

在iframe index.js中,我们使用window.onmessage侦听器来捕获消息

console.log("script starts")
$(function(){
    window.addEventListener("message", (e) => {
        if (e.data === 'update') $('body').append('<h1>Oh yeah !</h1>');
    });
})
console.log("script ends")

此示例在每次从父站点单击update到iframe时都会附加一个h1.

enter image description here

R相关问答推荐

当还使用模型列表时,是否可以使用forest_mode包的面板设置?(R统计分析)

Facet_wrap具有不同bin宽度值的图表

即使声明引发错误,R函数也会在第二次try 时返回结果

将一个载体的值相加,直到达到另一个载体的值

使用sensemakr和fixest feols模型(R)

从多个前置日期中获取最长日期

如何使用R Shiny中的条件面板仅隐藏和显示用户输入,同时仍允许运行基础计算?

格点中指数、双曲和反双曲模型曲线的正确绘制

derrr mutate case_when grepl不能在R中正确返回值

如何在所有绘图中保持条件值的 colored颜色 相同?

从外部文件读取多个值作为字符向量

线性模型斜率在减少原始数据时提供NA

如何从容器函数中提取conf并添加到ggplot2中?

有没有办法使用ggText,<;Sub>;&;<;sup>;将上标和下标添加到同一元素?

如何识别倒排的行并在R中删除它们?

提高圣彼得堡模拟的速度

有没有办法定制Plot(allEffects())面板标题?

为什么将负值向量提升到分数次方会得到NaN

R try Catch in the loop-跳过缺少的值并创建一个DF,显示跳过的内容

如何使投篮在R中保持一致