rshiny

How to update the button label of a fileInput after a button click?


Is there a way to update the button label of a fileInput button after the button was clicked and the triggered event has finished? I have my fileInput call customized to hide the progress bar and the text field. I'm also disabling the button once done. I want the "Get File" label of the button to change to something like for example "Done". I've found ways to use runjs() to change the entire button class, but I'm unsure how to specifically call the button label? Bonus points if I could also add an icon to my updated label.

All of this is easily achieved with a combination of an actionButton and file.choose(), but that doesn't work on shinyapps.io, so I need a workaround.

library(shiny)
library(shinyjs)

#custom function to hide the text field next to the button
fileInput2 <- function(..., label="") {
  temp <- fileInput(..., label=label)
  # Cut away the label
  temp$children[[1]] <- NULL
  # Cut away the input field (after label is cut, this is position 1 now)
  temp$children[[1]]$children[[2]] <- NULL
  # Remove input group classes (makes button flat on one side)
  temp$children[[1]]$attribs$class <- NULL
  temp$children[[1]]$children[[1]]$attribs$class <- NULL
  temp
}

ui <- fluidPage(
  shinyjs::useShinyjs(),
  tags$head(tags$style(".shiny-file-input-progress {display: none}")),
  fileInput2("file", label=NULL, buttonLabel="Get File", placeholder=NULL, width='175px'),
 
  )

server <- function(input, output, session) {
 
  observeEvent(input$file,{

    #...loading the data and doing something with it...

    shinyjs::disable("file") #disable the button
    runjs('$("#file").parents("span").addClass("disabled")') #make it look disabled
    #runjs("$('#file') ... now also update the button label...")
  })
}

shinyApp(ui,server)

Solution

  • Using shinyjs, you could e.g. include the following at a suitable position:

    runjs(
          "
          var button = $('#file').closest('.btn-file')[0]
          button.childNodes[0].nodeValue = 'Done';
          "
    )
    

    This would change the label of your input with id = "file" from "Get File" to "Done" as requested.

    If you want to add an icon in the updated text, you have to edit the innerHTML (add an i tag). Here is an example how the js could look like for a file icon from Font Awesome (shiny::icon(folder)).

    var myFileInputButton = $('#file').closest('.btn-file')[0]
    
    var i = document.createElement("i");
    i.className = "fa-solid fa-file"; 
    
    myFileInputButton.append(i); # use prepend() if it shall occur at the beginning
    

    It would look like this:

    enter image description here

    Notice that depending on which icon from which library you want to use, you may have to add some more code.