1
votes

I have a dataTableOutput that includes a column of textInputs, following the instructions from this question: Text Input Column in a table in shiny

I modified the code, so that the save button writes the data to a local csv file. However, I'm unable do get the content of the textInput. The column entries contain this kind of information:

<div class="form-group shiny-input-container">
  <label class="control-label shiny-label-null" for="cbox_1"></label>
  <input id="cbox_1" type="text" class="form-control" value=""/>
</div>

How do I get the actual value of the user input from cbox_1 and the other textInputs? Here is my complete code:

library(shiny)
library(DT)
library(dplyr)


shinyApp(
  ui <- fluidPage(DT::dataTableOutput("ruless"),
                  fluidRow(column(4, offset = 1, actionButton("save", "Save", width = 200),))),

  server <- function(input, output) {

    values <- reactiveValues(data = NULL)

    values$data <- as.data.frame(
      cbind(c("a", "d", "b", "c", "e", "f"),
            c(1463, 159, 54, 52, 52, 220),
            c(0.7315, 0.0795, 0.027, 0.026, 0.026, 0.11)
      )
    )

    shinyInput = function(FUN, len, id, ...) {
      #validate(need(character(len)>0,message=paste("")))
      inputs = character(len)
      for (i in seq_len(len)) {
        inputs[i] = as.character(FUN(paste0(id, i), label = NULL, ...))
      }
      inputs
    }

    dataExpTable <- reactive({

      data.frame(delete=shinyInput(textInput,nrow(values$data),"cbox_"), values$data)

    })

    output$ruless <- DT::renderDataTable({
      datatable(
        dataExpTable(),
        selection="multiple",
        escape = FALSE,
        filter = list(position = 'top', clear = FALSE),
        extensions = list("ColReorder" = NULL, "Buttons" = NULL),
        options = list(
          dom = 'BRrltpi',
          autoWidth=TRUE,
          lengthMenu = list(c(10, 50, -1), c('10', '50', 'All')),
          ColReorder = TRUE,
          preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
          drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } '),
          buttons = list(
            'copy',
            'print',
            list(
              extend = 'collection',
              buttons = c('csv', 'excel', 'pdf'),
              text = 'Download',
              selected = TRUE
            )
          )
        )
      )
    })

    observeEvent(input$save, {

      write.csv2(dataExpTable(), "test.csv", row.names = FALSE)

    })

  }
)
1

1 Answers

0
votes

A colleauge helped me with the solution. The content of the textInputs can be accessed via the Ids that are created by the shinyInput function. It combines a prefix with the row number of the given data frame. A csv output via the save button could look like this:

observeEvent(
  eventExpr   = input$save,
  handlerExpr = {
    out_col <- character(nrow(values$data))
    
    for (i in seq_len(nrow(values$data))) {
      
      out_col[i] <- input[[paste0("cbox_", i)]]

    }
    
    out_df <- cbind(out_col, values$data)
    
    write.csv2(out_df, "test.csv", row.names = FALSE)
  }
)

I tried a similar approach before, but it did not work. I removed these options when creating the datatable:

preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }')
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')

However, they are mandatory to access the textInputs via their Ids.