Home > database >  Add row number column to a reactive data frame in Shiny
Add row number column to a reactive data frame in Shiny

Time:05-15

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)
})
  • Related