0

I'm trying to add a "remove row" button in each row of a data table. I know that there are several answered questions with this topic, but I just can't make them work with my code. I took ideas from here and here and adapted them to my code but the problem is that the buttons aren't showing in the table and I have no way to know if the rows are actually being deleted.

Here's my code and a csv file with example data

library(shiny)
library(dplyr)
library(DT)
library(shinyjs)
library(shinythemes)

shinyInput <- function(FUN, len, id, ...) {
  inputs <- character(len)
  for (i in seq_len(len)) {
    inputs[i] <- as.character(FUN(paste0(id, i), ...))
  }
  inputs
}

ui <- fluidPage(
  useShinyjs(),
  theme = shinytheme("flatly"),
  tabsetPanel(
    id = "tabs",
    tabPanel("Section 1",
             sidebarLayout(
               sidebarPanel(
                 titlePanel("Select Variables"),
                 uiOutput('fondo'),
                 uiOutput('reg'),
                 uiOutput('seguro'),
                 uiOutput('prod_sap'),
                 hr(),
                 actionButton("addbutton","Add")
               ),
               mainPanel(
                 titlePanel("Preview"),
                 DT::dataTableOutput('courseTable'),
               )
             )
    )
  )
)

server <- function(input, output, session) {
  fondo_edo <- reactive ({
    read.csv("E:/Input Fondo-Edo-Reg_example.csv") 
  })
  
  output$fondo <- renderUI({
    times <- input$addbutton
    fondos_todos <- as.vector(unique(fondo_edo()$FONDO))
    div(id= letters[(times %% length(letters)) + 1],
        selectInput("fondo_selec","Fondo:", choices=fondos_todos,selectize = T))    
  })
  
  fondo_edo1 <- reactive({
    subset(fondo_edo(), FONDO %in% input$fondo_selec)
  })
  
  output$reg <- renderUI({
    reg_todos <- as.vector( unique(fondo_edo1()$REGIÓN) )
    selectInput("reg_selec","Región:", choices=reg_todos, selectize = F)    
  })
  
  output$seguro <- renderUI({
    times <- input$addbutton
    div(id=letters[(times %% length(letters))+1],
        selectInput("seguro_selec","Seguro agricultura protegida:", choices=c("","Cosecha_Esp", "Inversión", "Planta"), selectize = F))    
  })
  
  output$prod_sap <- renderUI({
    times <- input$addbutton
    div(id=letters[(times %% length(letters))+1],
        conditionalPanel("input.seguro_selec == 'Inversión'",
                         selectInput("prod_sap_selec","Nombre producto SAP:", choices= "Tradicional")),
        conditionalPanel("input.seguro_selec != 'Inversión'",
                         selectInput("prod_sap_selec2","Nombre producto SAP:",choices = c("","Establecimiento", "Mantenimiento", "Producción"), selectize = F)))
  })
  
  values <- reactiveValues()
  values$df <- data.frame("Fondo" = numeric(0), "Región"= numeric(0),
                          "Seguro agricultura protegida"= numeric(0), " " = numeric(0), check.names = F)
  proxyTable <- DT::dataTableProxy("tab")
  newEntry <- observe({
    if(input$addbutton > 0) {

      newLine <- isolate(c(input$fondo_selec, input$reg_selec,
                           ifelse(input$seguro_selec=="Planta", paste0(input$seguro_selec,"/",input$prod_sap_selec2),
                                  input$seguro_selec),
                           shinyInput(actionButton, input$addbutton,
                                      'button_', label = "Remove",
                                      onclick = sprintf('Shiny.onInputChange(\"remove_button\",  this.id)'))))
      isolate(values$df[nrow(values$df) + 1,] <-newLine)
    }
  })
  
  observeEvent(input$remove_button, {
    myTable <- values$df
    s <- as.numeric(strsplit(input$remove_button, "_")[[1]][2])
    myTable <- filter(myTable, row_number() != s)
    replaceData(proxyTable, myTable, resetPaging = FALSE)
    values$df <- myTable
  })
  
  output$courseTable <- DT::renderDataTable({values$df})
}


runApp(shinyApp(ui,server))

Thank you so much in advance

Adriana Huante
  • 352
  • 2
  • 11

1 Answers1

1

I renamed the special character in the header of your csv file to a simple o in English. Please try this and modify it back to your special character.

library(shiny)
library(dplyr)
library(DT)
library(shinyjs)
library(shinythemes)

getRemoveButton <- function(n, idS = "", lab = "Pit") {
  if (stringr::str_length(idS) > 0) idS <- paste0(idS, "-")
  ret <- shinyInput(actionButton, n,
                    'button_', label = "Remove",
                    onclick = sprintf('Shiny.onInputChange(\"%sremove_button_%s\",  this.id)' ,idS, lab))
  return (ret)
}

shinyInput <- function(FUN, n, id, ses, ...) {
  as.character(FUN(paste0(id, n), ...))
}

ui <- fluidPage(
  useShinyjs(),
  theme = shinytheme("flatly"),
  tabsetPanel(
    id = "tabs",
    tabPanel("Section 1",
             sidebarLayout(
               sidebarPanel(
                 titlePanel("Select Variables"),
                 uiOutput('fondo'),
                 uiOutput('reg'),
                 uiOutput('seguro'),
                 uiOutput('prod_sap'),
                 hr(),
                 actionButton("addbutton","Add")
               ),
               mainPanel(
                 titlePanel("Preview"), 
                 DTOutput('courseTable'),
               )
             )
    )
  )
)

server <- function(input, output, session) {
  fondo_edo <- reactive ({
    read.csv("C:\\My Disk Space\\_My Work\\RStuff\\GWS\\Fondo-Edo-Reg_example.csv", header=TRUE, sep=",") 
  })
  
  output$fondo <- renderUI({
    req(fondo_edo())
    times <- input$addbutton
    fondos_todos <- as.vector(unique(fondo_edo()$FONDO))
    div(id= letters[(times %% length(letters)) + 1],
        selectInput("fondo_selec","Fondo:", choices=fondos_todos,selectize = T))    
  })
  
  fondo_edo1 <- reactive({
    req(fondo_edo(),input$fondo_selec)
    subset(fondo_edo(), FONDO %in% input$fondo_selec)
  })
  
  output$reg <- renderUI({
    req(fondo_edo1())
    reg_todos <- as.vector( unique(fondo_edo1()$REGION) )
    selectInput("reg_selec","Region:", choices=reg_todos, selectize = F)
  })

  output$seguro <- renderUI({
    times <- input$addbutton
    div(id=letters[(times %% length(letters))+1],
        selectInput("seguro_selec","Seguro agricultura protegida:", choices=c("","Cosecha_Esp", "Inversión", "Planta"), selectize = F))
  })

  output$prod_sap <- renderUI({
    times <- input$addbutton
    div(id=letters[(times %% length(letters))+1],
        conditionalPanel("input.seguro_selec == 'Inversión'",
                         selectInput("prod_sap_selec","Nombre producto SAP:", choices= "Tradicional")),
        conditionalPanel("input.seguro_selec != 'Inversión'",
                         selectInput("prod_sap_selec2","Nombre producto SAP:",choices = c("","Establecimiento", "Mantenimiento", "Producción"), selectize = F)))
  })

  values <- reactiveValues()

  observe({
    n <- nrow(fondo_edo())
    values$df <- tibble(
      Row = 1:n,
      id = 1:n) %>%
      rowwise() %>%
      mutate(Remove = getRemoveButton(id, idS = "", lab = "Tab1")) %>% add_column(fondo_edo())
  })
  
  proxyTable <- DT::dataTableProxy("df")
  
  output$courseTable <- renderDT({
    DT::datatable(values$df,
                  options = list(pageLength = 25,
                                 dom        = "rt"),
                  rownames = FALSE,
                  escape   = FALSE,
                  editable = TRUE)
  })
  
  buttonCounter <- isolate(nrow(fondo_edo()))
  observeEvent(input$addbutton, {
    req(input$fondo_selec, input$reg_selec,input$seguro_selec,input$prod_sap_selec2)
    
    buttonCounter <<- buttonCounter + 1L
    myTable <- isolate(values$df)
    myTable <- bind_rows(
      myTable,
      tibble(Row = nrow(myTable) + 1) %>%
        mutate(id = buttonCounter,
               Remove = getRemoveButton(buttonCounter, idS = "", lab = "Tab1")) %>%  
        add_column(CLAVE.FONDO = 3, CVE_REGION = 66, 
                   Nom_Region = ifelse(input$seguro_selec=="Planta", paste0(input$seguro_selec,"/",input$prod_sap_selec2),input$seguro_selec),
                   FONDO = input$fondo_selec, REGION = input$reg_selec)
    )
    replaceData(proxyTable, myTable, resetPaging = FALSE)
    values$df <- myTable
  })

  observeEvent(input$remove_button_Tab1, {
    myTable <- values$df
    s <- as.numeric(strsplit(input$remove_button_Tab1, "_")[[1]][2])
    myTable <- filter(myTable, id != s)
    replaceData(proxyTable, myTable, resetPaging = FALSE)
    values$df <- myTable
  })

}

runApp(shinyApp(ui,server))

output

YBS
  • 19,324
  • 2
  • 9
  • 27
  • Thanks so much for your time and reply! the issue here is that the entire csv should not be loaded, it is only used to give the user a list from which to choose the imputs. PS. The csv that I provided has only few records and serves as an example but in the original one there are many more – Adriana Huante Jun 16 '21 at 19:59
  • Thank you so much!! I actually didn't want to add rows to the csv, instead I wanted to create a new table based on the user's input. However, your answer helped me solve the problem. In your code, instead of `add_column(fondo_edo())` I mutated the new columns that I wanted with values equal to `""` – Adriana Huante Jun 17 '21 at 14:49