Подтвердить что ты не робот

Как я могу обновить блестящий объект fileInput?

Я хочу создать диалоговое окно входного файла. Это просто, используя функцию fileInput.

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

enter image description here

После загрузки это выглядит так: enter image description here

Теперь я хочу reset элемент 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> 

Любые идеи?

PS. Я не хочу использовать реактивный renderUI здесь, чтобы повторно отобразить элемент ввода файла. Я бы предпочел пойти "путь обновления" (если есть такая вещь)...

4b9b3361

Ответ 1

Как отметил @Julien Navarre, это сводится к изменению некоторого HTML/CSS. Жюльен показал, как это сделать со стороны клиента. Остается показать, как это сделать со стороны сервера. То есть сервер будет вызывать функцию на стороне клиента, которая вернет обработчик ввода. Вы можете найти сообщение в блоге о передаче данных между сервером и клиентом, используя shiny здесь.

На стороне сервера ключевая функция session$sendCustomMessage, которая вызовет функцию обработчика resetFileInputHandler на стороне клиента. Идентификатор объекта ввода файла передается обработчику.

server.R

shinyServer(function(input, output, session) {

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

})

Теперь на стороне клиента нам нужно зарегистрировать функцию обработчика, которая будет вызываться сервером и выполнить необходимые изменения, как описано Жюльеном.

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%
    });
  ')
))

Нажатие кнопки теперь приведет к вызову сервера resetFileInputHandler на стороне клиента (конечно, кнопка предназначена только для демонстрационных пупок).

Вы можете найти приведенный выше код здесь или запустить его следующим образом

library(shiny)
runGist("8314905")

Внимание

Это решение остается не затронутым: имя файла, показанное справа для блестящего объекта

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

не изменяется. Наверное, это означало бы копаться в нем глубже. Предложения приветствуются.

Ответ 2

Возможно, это слишком поздно, но если вам все еще нужно,

Когда появится панель, вы увидите новый атрибут "стиль":

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

Все, что вам нужно сделать с JS, - это получить элемент со своим id ( "file1_progress" ) и установить параметр "видимость" атрибута "style" в "hidden".

Я приведу пример в Gist, вы можете увидеть его (и код), выполнив следующую команду:

shiny::runGist('8306992')

Надеюсь на эту помощь.

Ответ 3

Вот два способа сброса пользовательского интерфейса ввода файлов (как индикатор выполнения, так и отображаемое имя). Первый использует JavaScript, а второй использует renderUI.

Примеры включают в себя как кнопку "Очистить", так и необязательное раскрывающееся меню, которое сбрасывает входной интерфейс ввода файла при изменении выбора.

Пример 1 - использование JavaScript

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

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

$(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;");
    });

});

Пример 2 - с помощью renderUI

То же, что и выше, но (1) избавиться от active.js и связанного оператора include, (2) в ui.R заменить

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

с

uiOutput('resettableInput'),

и (3) в server.R add:

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

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

Обратите внимание, что здесь можно заключить несколько элементов пользовательского интерфейса в оператор list(), и все они будут повторно отображены. См. здесь.

Вы можете найти код для этих примеров здесь и здесь и выполните их следующим образом:

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

Ответ 4

Для тех, кто нуждается в этой функции в будущем: вы можете использовать функцию reset() из пакета shinyjs (начиная с версии 0.8) https://github.com/daattali/shinyjs