R Shiny Input Reactivity Error on Drag-and-Drop
我目前正在使用一些自定义js创建R Shiny应用,以提供拖放功能。 虽然拖放对单个文件非常有效,但是当我使用ShinyJS重置它时,再次上载同一文件不能正常工作。 我了解这是因为不会以重新输入具有相同名称的文件来触发onchange函数(无论文件内容是否已修改)
JS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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), "'/>","", file.name,""].join(''); document.getElementById("drop-area").appendChild(div); }; })(f); reader.readAsText(f); } }; |
Server.R(其中一部分用于查看文件输入):
1 2 3 4 5 6 7 8 9 10 11 12 | 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(仅相关部分):
1 2 3 4 5 6 7 | # 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相关的事件。 任何帮助深表感谢!
我看了一下并玩了一段时间,首先使其成为一个可行的示例。我认为拖放功能是一个有用的示例。它也正确处理多点。也有一些有趣的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 注释,以消除其他警告。 -
添加了一些输出字段(
inputdatafile 和rowsdatafile ),因此您可以跟踪input$datafile 中的内容-直到我不清楚真正的错误是什么,但这只是我... - 稍微更改了输出中的逻辑,以使重置功能按人们可能期望的方式工作(示例代码似乎仍然不完整)
- 可能还有其他一些我忘记的小事情。
这是代码:
JS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /*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), "'/>","", file.name,""].join(''); drpel = document.getElementById("drop-area"); drpel.appendChild(div); drpel.childNodes[0] ="Drop Area"+dropcount; }; })(f); reader.readAsText(f); dropcount++; } }; |
这是闪亮的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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) |
屏幕截图: