javascriptrshinyhandsontablerhandsontable

How to Validate and Clean Cell Range in Shiny App Before Passing to JavaScript?


I am currently working on a Shiny app where I want to have an input to select parts of an Rhandsontable. My goal is to do the validation and the cleaning of the cell range within the Shiny app and then pass the cleaned cell range to JavaScript to make the selection.

Here is the code I have so far (building on this post):

library(shiny)
library(htmlwidgets)
library(rhandsontable)

js <- "
function(el, x) {
  let hot = this.hot;
  Shiny.addCustomMessageHandler('handler_cell_range', function(message) {
    console.log(message);
    hot.selectCells([message]);
  });
}
"

ui <- fluidPage(
  textInput('cell_range', label = 'Cell range (start_row, start_col, end_col, end_row)',
            value = '1,2,3,4', width = '500px'),
  actionButton('bttn_cell_range', label = '', icon = icon('search')),
  rHandsontableOutput('table_raw')
)

server <- function(input, output, session) {
  # Render table
  output$table_raw <- renderRHandsontable({
    rhandsontable(iris) %>% onRender(js)
  })
  
  # Select range
  observeEvent(input$bttn_cell_range, {
    # Here there will be a lot of validation and cleaning of the cell range
    # before it can be passed to js
    
    # Clean cell range
    cr <- input$cell_range
    cr <- gsub(' ', '', cr) # Remove white space
    cr <- strsplit(cr, ',')[[1]] # Split by ,
    cr <- as.numeric(cr) - 1
    
    # Send to javascript to make the selection on the rhandsontable
    session$sendCustomMessage('handler_cell_range', message = cr)
  })
}

shinyApp(ui = ui, server = server)

I am wondering if this is the correct way to proceed.


Solution

  • Your code makes sense. Below I show how to use the shinyvalidate package for this problem. This allows to have a message (Invalid cell range) near the text input when the given cell range is not valid.

    I'm using a regex (^\\d+,\\d+,\\d+,\\d+$) to test whether the cell range has form number,number,number,number after white spaces removal. It seems to work but I'm not a regex master.

    library(shiny)
    library(shinyvalidate)
    
    ui <- fluidPage(
      br(),
      textInput("cell_range", "Enter cell range"),
      actionButton('bttn_cell_range', label = '', icon = icon('search'))
    )
    
    server <- function(input, output, session) {
      
      iv <- InputValidator$new()
      iv$add_rule(
        "cell_range",
        rule = function(cellRange) {
          test <- grepl("^\\d+,\\d+,\\d+,\\d+$", gsub(" ", "", cellRange))
          if(test) {
            return(NULL)
          } else {
            return("Invalid cell range")
          }
        }
      )
      iv$enable()
      
      observeEvent(input$bttn_cell_range, {
        
        req(iv$is_valid())
        
        # Clean cell range
        cr <- input$cell_range
        cr <- gsub(' ', '', cr) # Remove white space
        cr <- strsplit(cr, ',')[[1]] # Split by ,
        cr <- as.numeric(cr) - 1
        
        # Send to javascript to make the selection on the rhandsontable
        session$sendCustomMessage('handler_cell_range', message = cr)
      })
      
    }
    
    shinyApp(ui, server)