Village.Idyot
Village.Idyot

Reputation: 2043

Is there a simple way to sum columns in a table rendered in randsontable that expands with additional value inputs from the user?

In running the code posted at the bottom a table is rendered with rhandsontable whereby the user can add columns via click of the actionButton(), can add/delete rows by right-click of mouse when hovering over the table, and where the bottom row provides column sums.

However as illustrated below, values in inserted rows are not picked up in the column totals. Is there a way to have the column totals add up all rows even as they expand/contract? Without going through the brain damage of setting up rowNames (or row.names) as reactives?

enter image description here

Code:

library(rhandsontable)
library(shiny)

rowNames <- c('Hello A','Hello B','Hello C','Hello D','Total') 
data <- data.frame(row.names = rowNames,'Col 1' = c(10,20,-5,18,43),check.names = FALSE)

ui <- fluidPage(br(),
        rHandsontableOutput('hottable'),br(),
        actionButton("addCol", "Add column"),br(),br()
)

server <- function(input, output) {
  uiTable <- reactiveVal(data)
  observeEvent(input$hottable,{uiTable(hot_to_r(input$hottable))})
  
  output$hottable <- renderRHandsontable({
    rhandsontable(uiTable(),rowHeaderWidth = 100, useTypes = TRUE)
  })

  observe({
    req(input$hottable)
    DF <- hot_to_r(input$hottable)
    DF[setdiff(rowNames, "Total"),]
    DF["Total",] <- colSums(DF[setdiff(rowNames, "Total"),, drop = FALSE], na.rm = TRUE)
    uiTable(DF)
  })
  
  observeEvent(input$addCol, {
    newCol2 <- data.frame(c(10,20,-5,18,43))
    names(newCol2) <- paste("Col", ncol(hot_to_r(input$hottable)) + 1)
    uiTable(cbind(uiTable(), newCol2))
  })
  
}

shinyApp(ui,server)

Upvotes: 0

Views: 91

Answers (1)

Village.Idyot
Village.Idyot

Reputation: 2043

Very simple, I should have thought about it more before posting this. But maybe some other newbie will benefit from this. In the observe() function just replace rowNames (the list used to assign row names to the original dataframe) with rownames(DF) (which reads the actual names of the dataframe rows in its current state of play as it's being modified). Here´s the complete revised observer:

observe({
    req(input$hottable)
    DF <- hot_to_r(input$hottable)
    DF[setdiff(rownames(DF), "Total"),]
    DF["Total",] <- colSums(DF[setdiff(rownames(DF),"Total"),, drop = FALSE], na.rm = TRUE)
    uiTable(DF)
  })

Upvotes: 1

Related Questions