如何更新闪亮的fileInput对象?

时间:2022-05-19 07:22:32

I want to create an input file dialog. This is straightforward using the fileInput function.

我想创建一个输入文件对话框。使用fileInput函数很简单。

shinyUI(pageWithSidebar(
  headerPanel(""),
  sidebarPanel(
    fileInput("file", "Select a file")  
  ),
  mainPanel()
))

如何更新闪亮的fileInput对象?

After uploading it looks like this: 如何更新闪亮的fileInput对象?

上传后是这样的:

Now, I want to reset the inputFile element to the state it had before uploading. As there is no such function like updateFileInput, me being a JS/HTML rookie, I am not able to figure out how I could achieve that. The code output from fileInput("file", "Select a file") is the following.

现在,我想要将inputFile元素重置到上传之前的状态。因为没有像updateFileInput这样的函数,我是一个JS/HTML新手,所以我不知道如何实现它。从fileInput(“file”,“Select a file”)中的代码输出如下。

<label>Select a file</label>
<input id="file" type="file" accept="text/plain"/>
<div id="file_progress" class="progress progress-striped active shiny-file-input-progress">
  <div class="bar"></div>
  <label></label>
</div> 

Any ideas?

什么好主意吗?

PS. I do not want to use a reactive renderUI here to re-render the file input element. I'd rather want to go the 'update way' (if there is such a thing) ...

我不想在这里使用一个反应式renderUI来重新呈现文件输入元素。我宁愿选择“更新方式”(如果有的话)……

4 个解决方案

#1


8  

As @Julien Navarre pointed out, this boils down to modifying some HTML/CSS. Julien showed how to do that from the client side. What remains to be shown is how to do that from the server side. I.e. the server will invoke a function on the client side that will set back the input handler. You can find a blog post on passing data between server and client using shiny here.

正如@Julien Navarre指出的,这可以归结为修改一些HTML/CSS。朱利安在客户端展示了如何做到这一点。剩下要展示的是如何从服务器端实现这一点。例如,服务器将在客户端调用一个将设置输入处理程序的函数。您可以在这里找到一篇关于在服务器和客户机之间传递数据的博客文章。

On the server side the crucial function is session$sendCustomMessage which will call a the handler function resetFileInputHandler on the client side. The id of the file input object is passed to the handler.

在服务器端,关键的功能是会话$sendCustomMessage,它将在客户端调用处理程序函数resetFileInputHandler。文件输入对象的id被传递给处理程序。

server.R

server.R

shinyServer(function(input, output, session) {

  observe({
    input$btn
    session$sendCustomMessage(type = "resetFileInputHandler", "file1") 
  })

})

Now, on the client side we need to register a handler function that will be called by the server and perform the necessary changes as outlined by Julien.

现在,在客户端,我们需要注册一个处理器函数,服务器将调用它并执行必要的更改,如Julien所述。

ui.R

ui.R

shinyUI(bootstrapPage(

  fileInput('file1', 'Choose File'),
  actionButton("btn", "Trigger server to reset file input"),

  tags$script('
    Shiny.addCustomMessageHandler("resetFileInputHandler", function(x) {      
        var id = "#" + x + "_progress";      # name of progress bar is file1_progress
        var idBar = id + " .bar";  
        $(id).css("visibility", "hidden");   # change visibility
        $(idBar).css("width", "0%");         # reset bar to 0%
    });
  ')
))

Pressing the button will now cause the server to invoke the resetFileInputHandler on the client side (of course the button is just for demo puposes).

现在,按下按钮将导致服务器调用客户端上的resetFileInputHandler(当然,该按钮仅用于演示puthandler)。

You can find the above code here or run it like this

您可以在这里找到上面的代码,或者像这样运行它

library(shiny)
runGist("8314905")

Caution

谨慎

This solution leaves on aspect untouched:The file name shown to the right for the shiny object

这个解决方案没有涉及方面:向右显示闪亮对象的文件名

<input id="file1" type="file" class="shiny-bound-input">

is not altered. I guess that would mean digging deeper into it. Suggestions are welcome.

不改变。我猜这意味着要更深入地研究它。欢迎提出您的建议。

#2


5  

maybe it's too late, but if you still need it,

也许太晚了,但如果你还需要它,

When the bar appears you can see a new "style" attribute appear :

当栏出现时,可以看到一个新的“style”属性出现:

<div id="file1_progress" class="progress progress-striped shiny-file-input-progress" style="visibility: visible;">

All you have to do with JS, is to get the element with his id ("file1_progress") and to set the parameter "visibility" of the "style" attribute to "hidden".

您所要做的就是用他的id(“file1_progress”)来获取元素,并将“style”属性的参数“可视性”设置为“隐藏”。

I put an example on Gist, you can see it (and the code) by running the following command :

我在Gist上面放了一个例子,你可以通过下面的命令看到它(和代码):

shiny::runGist('8306992')

Hope this help.

希望这个有帮助。

#3


3  

Here are two ways of resetting the file input UI (both the progress bar and the displayed name). The first uses JavaScript and the second uses renderUI.

这里有两种重新设置文件输入UI的方法(进度条和显示的名称)。第一个使用JavaScript,第二个使用renderUI。

The examples include both a "Clear" button as well as an optional drop-down menu that resets the file input UI when the selection changes.

这些示例包括一个“Clear”按钮,以及一个可选的下拉菜单,该菜单在选择更改时重置文件输入UI。

Example 1 - using JavaScript

ui.R

ui.R

shinyUI(bootstrapPage(

    tags$head(
        tags$style(".clearButton {float:right; font-size:12px;}")
    ),

    headerPanel("Reset file input example"),

    sidebarPanel(
        HTML("<button id='clearFile1' class='action-button clearButton'>Clear</button>"),
        fileInput('file1', NULL, width="80%"),

        selectInput('uploadFormat', label = "Select upload format", 
            choices = c(
                "Option 1" = 'f1',
                "Option 2" = 'f2',
                "Option 3" = 'f3'),
            selected = 'f1')
    ),

    mainPanel(
        h4("Summary"),
        verbatimTextOutput("summary")
    ),
    singleton(includeScript("active.js"))
))

server.R

server.R

shinyServer(function(input, output, session) {

    values <- reactiveValues(
        file1 = NULL
    )

    observe({
        input$clearFile1
        input$uploadFormat
        values$file1 <- NULL
    })

    observe({
        values$file1 <- input$file1
    })

    output$summary <- renderText({
        return(paste("Uploaded file: ", values$file1$name))
    })

})

active.js

active.js

$(document).ready(function() {

    /* clear file button control */
    var fileControl = $("#file1");

    $("#clearFile1").on("click", function () {
        fileControl.replaceWith( fileControl = fileControl.clone( true ) );
        $("#file1_progress").hide();
    });

    $("#uploadFormat").on("change", function () {
        fileControl.replaceWith( fileControl = fileControl.clone( true ) );
        $("#file1_progress").hide();
    });

    /* file input progress bar control */
    $( "#file1" ).change(function() {
      document.getElementById("file1_progress").setAttribute('style', "height:20px; margin-top:5px;");
    });

});

Example 2 - using renderUI

Same as above, but (1) get rid of active.js and the related include statement, (2) in ui.R replace

和上面一样,但是(1)去掉活动。js和相关的include语句(2)在ui中。R取代

fileInput('file1', NULL, width="80%"),

with

uiOutput('resettableInput'),

and (3) in server.R add:

和(3)服务器。R添加:

    output$resettableInput <- renderUI({
        input$clearFile1
        input$uploadFormat

        fileInput('file1', NULL, width="80%")
    })

Note that one could enclose multiple UI elements in a list() statement here and they would all be re-rendered. See here.

注意,可以在这里的列表()语句中包含多个UI元素,它们都将被重新呈现。在这里看到的。

You can find the code for these examples here and here, and run them like so:

你可以在这里和这里找到这些示例的代码,并像这样运行它们:

library(shiny)
shiny::runGist('0c2a98a0236f1257fd45')
shiny::runGist('bc09d77fa92457e094c8')

#4


3  

For anyone who needs this functionality in the future: you can use the reset() function from the shinyjs package (since version 0.8) https://github.com/daattali/shinyjs

对于将来需要此功能的任何人:您可以使用shinyjs包中的reset()函数(因为版本0.8)https://github.com/daattali/shinyjs。

#1


8  

As @Julien Navarre pointed out, this boils down to modifying some HTML/CSS. Julien showed how to do that from the client side. What remains to be shown is how to do that from the server side. I.e. the server will invoke a function on the client side that will set back the input handler. You can find a blog post on passing data between server and client using shiny here.

正如@Julien Navarre指出的,这可以归结为修改一些HTML/CSS。朱利安在客户端展示了如何做到这一点。剩下要展示的是如何从服务器端实现这一点。例如,服务器将在客户端调用一个将设置输入处理程序的函数。您可以在这里找到一篇关于在服务器和客户机之间传递数据的博客文章。

On the server side the crucial function is session$sendCustomMessage which will call a the handler function resetFileInputHandler on the client side. The id of the file input object is passed to the handler.

在服务器端,关键的功能是会话$sendCustomMessage,它将在客户端调用处理程序函数resetFileInputHandler。文件输入对象的id被传递给处理程序。

server.R

server.R

shinyServer(function(input, output, session) {

  observe({
    input$btn
    session$sendCustomMessage(type = "resetFileInputHandler", "file1") 
  })

})

Now, on the client side we need to register a handler function that will be called by the server and perform the necessary changes as outlined by Julien.

现在,在客户端,我们需要注册一个处理器函数,服务器将调用它并执行必要的更改,如Julien所述。

ui.R

ui.R

shinyUI(bootstrapPage(

  fileInput('file1', 'Choose File'),
  actionButton("btn", "Trigger server to reset file input"),

  tags$script('
    Shiny.addCustomMessageHandler("resetFileInputHandler", function(x) {      
        var id = "#" + x + "_progress";      # name of progress bar is file1_progress
        var idBar = id + " .bar";  
        $(id).css("visibility", "hidden");   # change visibility
        $(idBar).css("width", "0%");         # reset bar to 0%
    });
  ')
))

Pressing the button will now cause the server to invoke the resetFileInputHandler on the client side (of course the button is just for demo puposes).

现在,按下按钮将导致服务器调用客户端上的resetFileInputHandler(当然,该按钮仅用于演示puthandler)。

You can find the above code here or run it like this

您可以在这里找到上面的代码,或者像这样运行它

library(shiny)
runGist("8314905")

Caution

谨慎

This solution leaves on aspect untouched:The file name shown to the right for the shiny object

这个解决方案没有涉及方面:向右显示闪亮对象的文件名

<input id="file1" type="file" class="shiny-bound-input">

is not altered. I guess that would mean digging deeper into it. Suggestions are welcome.

不改变。我猜这意味着要更深入地研究它。欢迎提出您的建议。

#2


5  

maybe it's too late, but if you still need it,

也许太晚了,但如果你还需要它,

When the bar appears you can see a new "style" attribute appear :

当栏出现时,可以看到一个新的“style”属性出现:

<div id="file1_progress" class="progress progress-striped shiny-file-input-progress" style="visibility: visible;">

All you have to do with JS, is to get the element with his id ("file1_progress") and to set the parameter "visibility" of the "style" attribute to "hidden".

您所要做的就是用他的id(“file1_progress”)来获取元素,并将“style”属性的参数“可视性”设置为“隐藏”。

I put an example on Gist, you can see it (and the code) by running the following command :

我在Gist上面放了一个例子,你可以通过下面的命令看到它(和代码):

shiny::runGist('8306992')

Hope this help.

希望这个有帮助。

#3


3  

Here are two ways of resetting the file input UI (both the progress bar and the displayed name). The first uses JavaScript and the second uses renderUI.

这里有两种重新设置文件输入UI的方法(进度条和显示的名称)。第一个使用JavaScript,第二个使用renderUI。

The examples include both a "Clear" button as well as an optional drop-down menu that resets the file input UI when the selection changes.

这些示例包括一个“Clear”按钮,以及一个可选的下拉菜单,该菜单在选择更改时重置文件输入UI。

Example 1 - using JavaScript

ui.R

ui.R

shinyUI(bootstrapPage(

    tags$head(
        tags$style(".clearButton {float:right; font-size:12px;}")
    ),

    headerPanel("Reset file input example"),

    sidebarPanel(
        HTML("<button id='clearFile1' class='action-button clearButton'>Clear</button>"),
        fileInput('file1', NULL, width="80%"),

        selectInput('uploadFormat', label = "Select upload format", 
            choices = c(
                "Option 1" = 'f1',
                "Option 2" = 'f2',
                "Option 3" = 'f3'),
            selected = 'f1')
    ),

    mainPanel(
        h4("Summary"),
        verbatimTextOutput("summary")
    ),
    singleton(includeScript("active.js"))
))

server.R

server.R

shinyServer(function(input, output, session) {

    values <- reactiveValues(
        file1 = NULL
    )

    observe({
        input$clearFile1
        input$uploadFormat
        values$file1 <- NULL
    })

    observe({
        values$file1 <- input$file1
    })

    output$summary <- renderText({
        return(paste("Uploaded file: ", values$file1$name))
    })

})

active.js

active.js

$(document).ready(function() {

    /* clear file button control */
    var fileControl = $("#file1");

    $("#clearFile1").on("click", function () {
        fileControl.replaceWith( fileControl = fileControl.clone( true ) );
        $("#file1_progress").hide();
    });

    $("#uploadFormat").on("change", function () {
        fileControl.replaceWith( fileControl = fileControl.clone( true ) );
        $("#file1_progress").hide();
    });

    /* file input progress bar control */
    $( "#file1" ).change(function() {
      document.getElementById("file1_progress").setAttribute('style', "height:20px; margin-top:5px;");
    });

});

Example 2 - using renderUI

Same as above, but (1) get rid of active.js and the related include statement, (2) in ui.R replace

和上面一样,但是(1)去掉活动。js和相关的include语句(2)在ui中。R取代

fileInput('file1', NULL, width="80%"),

with

uiOutput('resettableInput'),

and (3) in server.R add:

和(3)服务器。R添加:

    output$resettableInput <- renderUI({
        input$clearFile1
        input$uploadFormat

        fileInput('file1', NULL, width="80%")
    })

Note that one could enclose multiple UI elements in a list() statement here and they would all be re-rendered. See here.

注意,可以在这里的列表()语句中包含多个UI元素,它们都将被重新呈现。在这里看到的。

You can find the code for these examples here and here, and run them like so:

你可以在这里和这里找到这些示例的代码,并像这样运行它们:

library(shiny)
shiny::runGist('0c2a98a0236f1257fd45')
shiny::runGist('bc09d77fa92457e094c8')

#4


3  

For anyone who needs this functionality in the future: you can use the reset() function from the shinyjs package (since version 0.8) https://github.com/daattali/shinyjs

对于将来需要此功能的任何人:您可以使用shinyjs包中的reset()函数(因为版本0.8)https://github.com/daattali/shinyjs。