【问题标题】:R Shiny Input Reactivity Error on Drag-and-Drop拖放时的 R Shiny 输入反应性错误
【发布时间】:2017-05-06 10:20:23
【问题描述】:

我目前正在创建一个带有一些自定义 js 的 R Shiny 应用程序,以提供拖放功能。虽然拖放对单个文件非常有效,但当我使用 shinyJS 重置它时,再次上传相同的文件无法正常工作。我知道这是因为重新输入同名文件时不会触发 onchange 函数(无论文件内容是否已被修改)

JS:

var datasets = {};
var dragOver = function(e) { e.preventDefault(); };

var dropData = function(e) {
    e.preventDefault();
    handleDrop(e.dataTransfer.files);
};

var removeFiles = function(e){
    jQuery('#datafile').empty();
}

var handleDrop = function(files) {
    for (var i = 0, f; f = files[i]; i++) {
    var reader = new FileReader();

    reader.onload = (function(file) {
        return function(e) {
        datasets[file.name.toLowerCase()] = e.target.result;
        Shiny.onInputChange("datafile", datasets);
        var div = document.createElement("div");
        var src = "https://cdn0.iconfinder.com/data/icons/office/512/e42-512.png";
        div.id = "datasets";
        div.innerHTML = [
            "<img class='thumb' src='", src, "' title='", encodeURI(file.name),
            "'/>", "<br>", file.name, "<br>"].join('');
        document.getElementById("drop-area").appendChild(div);
        };
    })(f);
    reader.readAsText(f);
    }
};

Server.R(查看文件输入的部分):

observeEvent(input$datafile, {
    infile <- input$datafile
    if (is.null(infile)) {
      # User has not uploaded a file yet
      return(NULL)
    }

    # CLEAN FILE
    name <- names(input$datafile)[1]
    csvFile <- read.csv(text=input$datafile[[name]])

  output$dataTable <- renderDataTable(csvFile , options = list(scrollX = '1100px') )

}

ui.R(只是相关部分):

   # DRAG AND DROP FILE INPUT
   h3(id="data-title", "Drop Datasets"),

   div(class="col-xs-12", id="drop-area", ondragover="dragOver(event)", 
       ondrop="dropData(event)" , onClick="fallback(event)"),

   div(onClick="removeFiles(event)", actionButton(inputId="resetAutomaticInput", label="Reset Input")

我不明白如何让我的闪亮值反应触发与 input$datafile 关联的事件。非常感谢任何帮助!

【问题讨论】:

  • 我为此使用了一种解决方法。除了input$datafile,引入Shiny.onInputChange("trigger", Math.random());并使用observeEvent(input$trigger, ...,而不是依赖input$datafile,...

标签: javascript r drag-and-drop shiny reactive-programming


【解决方案1】:

我看了一下这个并玩了一段时间,首先将它变成一个工作示例。我认为拖放功能是一个有用的例子。它也可以正确处理多点。其中也有一些有趣的 javascript 结构——至少对我来说是这样。

为了解决这个问题,我没有像 BigDataScientist 建议的那样使用随机数,而是使用了一个对其他事情也可能有用的计数。

总共进行了这些更改:

  • 将片段完成成一个完整的 Shiny 工作示例,并将其保存到自己的目录中。
  • 将 javascript 代码放入保存 Shiny 代码的目录下名为 www 的子目录中。
  • 在 UI 代码中添加了 tag$head(tag$script(... 语句以加载该 JavaScript。
  • drop-area div 添加了一些innerhtml 文本,以便将其放入其中。
  • 在 javascript 中添加了 dropcount
  • 更改了 html,以便 dropcount 将回显到 drop-area div。
  • 将输出更改为verbatumPrintOutput,这样您就可以在更小的区域内看到更多的数据框。
  • 在输出中添加了更多字段,以便您更好地查看 input$datafile 中的内容。
  • 将 JS for 循环更改为不会产生警告的内容。
  • 在顶部添加了 jslint 评论以消除另一个警告。
  • 添加了一些输出字段(inputdatafilerowsdatafile),以便您可以跟踪 input$datafile 中的内容 - 直到我这样做之前我不清楚真正的错误是什么,但这只是我......
  • 稍微更改了输出中的逻辑,以使重置功能按照人们可能期望的方式工作(示例代码似乎仍然不完整)
  • 可能还有一些我忘记的小事。

代码如下:

JS:

/*jshint loopfunc:true */ // git rid of warning
var datasets = {};
var dragOver = function(e) { e.preventDefault(); };

var dropData = function(e) {
  e.preventDefault();
  handleDrop(e.dataTransfer.files);
};
var dropcount=0;

var removeFiles = function(e){
    txt = "Drop Area "+dropcount;
    jQuery('#drop-area').html(txt);
    datasets = {};
    Shiny.onInputChange("datafile", datasets);
};
var handleDrop = function(files) {
  for (var i = 0; i<files.length; i++) {
    f = files[i];
    var reader = new FileReader();

    reader.onload = (function(file) {
      return function(e) {
        datasets[file.name.toLowerCase()+'|'+dropcount] = e.target.result;
        Shiny.onInputChange("datafile", datasets);
        var div = document.createElement("div");
        var src = "https://cdn0.iconfinder.com/data/icons/office/512/e42-512.png";
        div.id = "datasets";
        div.innerHTML = [
          "<img class='thumb' src='", src, "' title='", encodeURI(file.name),
          "'/>", "<br>", file.name, "<br>"].join('');
        drpel = document.getElementById("drop-area");
        drpel.appendChild(div);
        drpel.childNodes[0] = "Drop Area "+dropcount;
      };
    })(f);
    reader.readAsText(f);
    dropcount++;
  }
};

这是闪亮的:

library(plotly)
library(htmlwidgets)
library(shiny)
library(ggplot2)

ui <- shinyUI(fluidPage(

  tags$head(tags$script(type="text/javascript", src = "fileUp.js")),

  # DRAG AND DROP FILE INPUT
  h3(id="data-title", "Drop Datasets"),

  div(class="col-xs-12",id="drop-area",ondragover="dragOver(event)", 
      ondrop="dropData(event)",onClick="fallback(event)","Drop Area"),

  div(onClick="removeFiles(event)",
      actionButton(inputId="resetAutomaticInput",label="Reset Input"),
      verbatimTextOutput("inputdatafile"),
      verbatimTextOutput("rowsdatafile"),
      verbatimTextOutput("dataTable"))
))    
server <- shinyServer(function(input, output) {

  observeEvent(input$datafile, {
    infile <- input$datafile
    if (length(infile)==0) {
      # User has not uploaded a file yet
        return(NULL)
    }    
    # CLEAN FILE
    name <- names(input$datafile)[length(infile)]
    csvFile <- reactive(
      if (length(input$datafile)>0){
        read.csv(text=input$datafile[[name]])
      }
    )

    output$dataTable <- renderPrint(csvFile())
    output$inputdatafile <- renderPrint(names(input$datafile))
    output$rowsdatafile <- renderPrint(sapply(input$datafile,nchar))
  })
})
shinyApp(ui, server)

还有一个屏幕截图:

【讨论】:

  • 虽然你的回答对我不起作用,但它让我思考。检查我的答案为什么。谢谢!
  • 嗯,这和我做的有什么不同?我还将总掉落数附加到名称中。
  • 我的错,你是对的。您的代码只是使用“drpel”引发错误并且无法正常工作。我只想添加“ datasets = {};”进入 removeFiles() 函数,你的答案是对的!
  • 当我把它复制到那里时一定是一个错字。在我的测试中运行良好。回来后会修。
  • 好的,做了更多的修改,使它作为一个例子更完整和有用,我认为没有更多的错别字了。请注意,您现在也可以投票 :)
猜你喜欢
  • 2014-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-27
  • 1970-01-01
  • 2014-05-11
  • 2016-10-11
相关资源
最近更新 更多