Search code examples
javascripthtmlrshinyrhandsontable

How to format numbers in a specific row using js in a table rendered with rhandsontable?


In the simplified code at the bottom of this post, I believe it is js that is used for formatting outputs of the table rendered using rhandsontable. I play around with row/column formatting with some success in the js section of the code. However, as illustrated below, how would I format row 2 of the table so that it is shown as an integer (rounded to digits = 0, so there are no decimals) with commas separating the thousands, for all columns as they are added?

I've played around with the usual formatC(), etc., with no luck. Looks like the answer might lie in js.

enter image description here

Code:

library(rhandsontable)
library(shiny)

mydata <- data.frame('Series 1' = c(1,2000.39,3,4),check.names = FALSE)

rownames(mydata) <- c('A','B','C','D') 

ui <- fluidPage(
  rHandsontableOutput("mytable"),
  textInput('NewCol', 'Enter new column name'),
  actionButton("goButton", "Update Table")
)

server <- function(input, output) {
  output$mytable = renderRHandsontable(df())
  
  df <- eventReactive(input$goButton, {
    if(input$NewCol!="" && !is.null(input$NewCol) && input$goButton>0){
      newcol <- data.frame(NROW(mydata))
      newcol[2,] <- c(1234.22)
      names(newcol) <- input$NewCol
      mydata <<- cbind(mydata, newcol)
    }
    rhandsontable(mydata,rowHeaderWidth = 100)%>%
      hot_cols(
        renderer = "function(instance, td, row, col, prop, value, cellProperties) {
        Handsontable.renderers.NumericRenderer.apply(this, arguments);
          // format as integers first 2 rows:
            if(row == 0 || row == 1){td.innerHTML = `${value}`;} 
          // shade 2nd row:
            if(row == 1){td.style.background='#eff0f1'} 
          // format as % the 2nd set of 2 rows:
            if(row == 2 || row == 3){td.innerHTML = `${Number.parseFloat(value*100)}%`} 
        }") %>% 
      hot_row(c(2), readOnly = TRUE) # makes row 2 read-only
    
  }, ignoreNULL = FALSE)
  observe(if (!is.null(input$mytable)) mydata <<- hot_to_r(input$mytable))
}

shinyApp(ui,server)

Solution

  • One option would be to use the formatter functions provided by the Internationalization API to format your numbers using e.g. Intl.NumberFormat. To get a comma as the grouping mark you could use e.g. US locale:

    library(rhandsontable)
    library(shiny)
    
    mydata <- data.frame('Series 1' = c(1,2000.39,3,4),check.names = FALSE)
    
    rownames(mydata) <- c('A','B','C','D') 
    
    ui <- fluidPage(
      rHandsontableOutput("mytable"),
      textInput('NewCol', 'Enter new column name'),
      actionButton("goButton", "Update Table")
    )
    
    server <- function(input, output) {
      output$mytable = renderRHandsontable(df())
      
      df <- eventReactive(input$goButton, {
        if(input$NewCol!="" && !is.null(input$NewCol) && input$goButton>0){
          newcol <- data.frame(NROW(mydata))
          newcol[2,] <- c(1234.22)
          names(newcol) <- input$NewCol
          mydata <<- cbind(mydata, newcol)
        }
        rhandsontable(mydata,rowHeaderWidth = 100)%>%
          hot_cols(
            renderer = "function(instance, td, row, col, prop, value, cellProperties) {
              Handsontable.renderers.NumericRenderer.apply(this, arguments);
              
              const formatter = new Intl.NumberFormat('en-US', {
                maximumFractionDigits: 0
              })
              
              // format as integers first 2 rows:
                if(row == 0 || row == 1){td.innerHTML = `${value}`;} 
              // shade 2nd row:
                if(row == 1){td.style.background='#eff0f1'} 
              // format as % the 2nd set of 2 rows:
                if(row == 2 || row == 3){td.innerHTML = `${Number.parseFloat(value*100)}%`} 
              
              // format second row as numbers:
                if(row == 1) { td.innerHTML = `${formatter.format(value)}`;} 
            
             }
          ") %>% 
          hot_row(c(2), readOnly = TRUE) # makes row 2 read-only
        
      }, ignoreNULL = FALSE)
      observe(if (!is.null(input$mytable)) mydata <<- hot_to_r(input$mytable))
    }
    
    shinyApp(ui,server)
    

    enter image description here