I'm working on a R Shiny app where a user has control of a data table. They can add new rows to the table, or remove any of the existing rows. My desire is to have a Remove button embedded in the table where the user can click this button and that row will be deleted.
Below is the current status of my solution, however it doesn't work consistently. The add button works consistently, however sometimes the remove button is not recognized.
```
library(DT)
getRemoveButtons <- 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, len, id, ses, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))
}
inputs
}
ui = shinyUI(fluidPage(
fluidRow(DT::dataTableOutput("myTable")),
fluidRow(actionButton("addRow", label = "Add Row",
icon = icon("plus"))))
)
server = function(input, output) {
values <- reactiveValues()
values$tab <- tibble(
Row = 1:3L,
Remove = getRemoveButtons(3, idS = "", lab = "Tab1"))
proxyTable <- DT::dataTableProxy("tab")
output$myTable <- DT::renderDataTable({
DT::datatable(values$tab,
options = list(pageLength = 25,
dom = "rt"),
rownames = FALSE,
escape = FALSE,
editable = TRUE)
})
observeEvent(input$remove_button_Tab1, {
myTable <- values$tab
s <- as.numeric(strsplit(input$remove_button_Tab1, "_")[[1]][2])
myTable <- filter(myTable, row_number() != s)
myTable <-
mutate(myTable,
Remove = getRemoveButtons(nrow(myTable), idS = "", lab = "Tab1"))
replaceData(proxyTable, myTable, resetPaging = FALSE)
values$tab <- myTable
})
observeEvent(input$addRow, {
myTable <- isolate(values$tab)
myTable <- select(myTable, Row)
myTable <- bind_rows(
myTable,
tibble(Row = nrow(myTable) + 1))
myTable <- mutate(myTable,
Remove = getRemoveButtons(nrow(myTable), idS = "", lab = "Tab1"))
replaceData(proxyTable, myTable, resetPaging = FALSE)
values$tab <- myTable
})
}
shinyApp(ui = ui, server = server)
When using a DataSet or DataTable in conjunction with a DataAdapter and a relational data source, use the Delete method of the DataRow to remove the row. The Delete method marks the row as Deleted in the DataSet or DataTable but does not remove it.
In general, the rows are removed by using the row index number but we can do the same by using row names as well. This can be done by storing the row names that should be removed in a vector and then removing through subsetting with single square brackets as shown in the below examples.
Ok, I have it working now. The issue was trying to reuse the ids for the buttons. By creating a counter and assigning each new button an id that's never been used before it now works perfectly. Modified code below.
```
library(DT)
library(dplyr)
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 = shinyUI(fluidPage(
fluidRow(DT::dataTableOutput("myTable")),
fluidRow(actionButton("addRow", label = "Add Row",
icon = icon("plus"))))
)
server = function(input, output) {
buttonCounter <- 3L
values <- reactiveValues()
values$tab <- tibble(
Row = 1:3L,
id = 1:3L) %>%
rowwise() %>%
mutate(Remove = getRemoveButton(id, idS = "", lab = "Tab1"))
proxyTable <- DT::dataTableProxy("tab")
output$myTable <- DT::renderDataTable({
DT::datatable(values$tab,
options = list(pageLength = 25,
dom = "rt"),
rownames = FALSE,
escape = FALSE,
editable = TRUE)
})
observeEvent(input$remove_button_Tab1, {
myTable <- values$tab
s <- as.numeric(strsplit(input$remove_button_Tab1, "_")[[1]][2])
myTable <- filter(myTable, id != s)
replaceData(proxyTable, myTable, resetPaging = FALSE)
values$tab <- myTable
})
observeEvent(input$addRow, {
buttonCounter <<- buttonCounter + 1L
myTable <- isolate(values$tab)
myTable <- bind_rows(
myTable,
tibble(Row = nrow(myTable) + 1) %>%
mutate(id = buttonCounter,
Remove = getRemoveButton(buttonCounter, idS = "", lab = "Tab1")))
replaceData(proxyTable, myTable, resetPaging = FALSE)
values$tab <- myTable
})
}
shinyApp(ui = ui, server = server)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With