I am trying to add a row index column to a reactive data frame created on-the-fly from user inputs. I am able to do this outside of Shiny using the tibble::rowid_to_column function but cannot make it work in the below Shiny app (line 44). Can someone please provide guidance on how to make it work? Also, when I delete a row from the data frame, how can we make rowid numbers sequential again? Thanks.
library(shiny)
library(DT)
library(tidyverse)
input_data <- data.frame(
# rowid = double(),
input1 = character(),
input2 = double(),
stringsAsFactors = FALSE)
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(
selectInput("input1",
"Input 1",
choices = c("Value 1", "Value 2", "Value 3")),
numericInput("input2",
"Input 2",
value = 100),
actionButton("add_btn",
"Add Row"),
actionButton("delete_btn",
"Delete Row"),
actionButton("reset_btn",
"Reset"),
position = "left"
),
mainPanel(
DT::dataTableOutput("input_table")
)
)
)
server <- function(input, output) {
input_table <- reactiveVal(input_data)
observeEvent(input$add_btn, {
t = rbind(input_table(), data.frame(col1 = input$input1, col2 = input$input2))
# %>%
# cbind(tibble::rowid_to_column("rowid"))
input_table(t)
})
observeEvent(input$delete_btn, {
t = input_table()
print(input$input_table_rows_selected)
if (!is.null(input$input_table_rows_selected)) {
t <- t[-input$input_table_rows_selected,]
}
input_table(t)
})
observeEvent(input$reset_btn, {
input_table(input_data)
})
output$input_table <- DT::renderDataTable({
datatable(input_table())
})
}
shinyApp(ui = ui, server = server)
CodePudding user response:
rowid_to_column()
adds the row names of a tibble and adds them as a column to the data frame. This won't work for you: once you have added the rownames in a column rowid
, you cannot add that column a second time. Also, the function returns the entire tibble with the new column added, so it makes no sense to cbind()
the output of rowid_to_column()
it to the tibble.
I suggest the following changes to your code:
Define the initial Table with the rowid column:
input_data <- tibble(
rowid = integer(),
input1 = character(),
input2 = double()
)
In the first observer, change the code to this:
observeEvent(input$add_btn, {
new_row <- tibble(rowid = nrow(input_table()) 1,
input1 = input$input1,
input2 = input$input2)
t = bind_rows(input_table(), new_row)
input_table(t)
})
This creates a new row with the appropriate rowid and then adds it to the table.
In order to have the expected rowids after deletion of a row you simply have to redefine the rowids each time a row is delted:
observeEvent(input$delete_btn, {
t <- input_table()
print(input$input_table_rows_selected)
if (!is.null(input$input_table_rows_selected)) {
t <- t[-input$input_table_rows_selected, ]
t$rowid <- 1:nrow(t)
}
input_table(t)
})
And when rendering the output table, you have to suppress the row names:
output$input_table <- DT::renderDataTable({
datatable(input_table(), rownames = FALSE)
})