Search code examples
rshinyrhandsontable

Is there a way to force a character limit in an rhandsontable within R Shiny?


I have a simple Shiny App and I want to prevent the user of the app from saving and exporting data if they enter in too many characters in the "Project Name" column when modifying the rhandsontable. I found a way to make the letters red as a warning that you are entering too many characters, but I am struggling with finding a way of actually preventing the user from saving the data. Here is my attept at doing that and I cannot figure it out. As always any help would be appreciated.


library(shiny)
library(rhandsontable)
library(tibble)


project_data <- tibble(
  "Project Name" = c("Project A", "Project B", "Project C"),
  "Project Cost" = c(10000, 15000, 20000),
  "Project Status" = c("In Progress", "Completed", "In Progress"),
  "Project Start Date" = as.Date(c("2023-01-15", "2022-05-10", "2023-03-20"))
)


modified_data <- reactiveVal(project_data)

ui <- fluidPage(
  titlePanel("Project Data"),
  fluidRow(
    column(12,
           rHandsontableOutput("table")
    )
  ),
  fluidRow(
    column(12,
           actionButton("saveButton", "Save")
    )
  )
)

server <- function(input, output, session) {
  
  modified_data <- reactiveVal(project_data)
  
  
  
  
  output$table <- renderRHandsontable({
    rhandsontable(modified_data()) %>%
      hot_col("Project Name", allowInvalid = FALSE, renderer = "
        function(instance, td, row, col, prop, value, cellProperties) {
          Handsontable.renderers.TextRenderer.apply(this, arguments);
          if (value.length > 20) {
            td.style.color = 'red';
          }
        }
      ")
    
    
    
  })
  
  
  observeEvent(input$saveButton, {
    
    invalid_values <- modified_data()$`Project Name`[nchar(modified_data()$`Project Name`) > 20]
    
    if (length(invalid_values) == 0) {
      saved_data <- hot_to_r(input$table)
      write.csv(saved_data, file = "saved_project_data.csv", row.names = FALSE)
      showModal(
        modalDialog(
          title = "Success",
          "Data has been saved to 'saved_project_data.csv'.",
          easyClose = TRUE
        )
      )
    } else {
      showModal(
        modalDialog(
          title = "Warning",
          "DATA HAS NOT BEEN SAVED",
          easyClose = TRUE
        )
      )
      
    }
  })
}

shinyApp(ui, server)

Solution

  • You need a validator here. Say you want to allow the user to only enter strings of maximum length 10 in the project name column, then the following would prevent saving a longer character value into a cell and print an error message in case of the user tries to do this.

    validator = "
                function (value, callback) {
                    setTimeout(function(){
                        callback(value.length < 11);
                        if (value.length > 10) {
                            alert('more than 10 characters!');
                        }
                    }, 1000)
                }
                "
    

    enter image description here

    library(shiny)
    library(rhandsontable)
    library(tibble)
    
    
    project_data <- tibble(
        "Project Name" = c("Project_A", "Project_B", "Project_C"),
        "Allowed" = c("yes", "no", "")
    )
    
    
    modified_data <- reactiveVal(project_data)
    
    ui <- fluidPage(titlePanel("Project Data"),
                    fluidRow(column(12,
                                    rHandsontableOutput("table"))),
                    fluidRow(column(12,
                                    actionButton(
                                        "saveButton", "Save"
                                    ))))
    
    server <- function(input, output, session) {
        modified_data <- reactiveVal(project_data)
        
        
        
        
        output$table <- renderRHandsontable({
            rhandsontable(modified_data()) %>%
                hot_col(
                    "Project Name",
                    allowInvalid = FALSE,
                    validator = "
                                function (value, callback) {
                                    setTimeout(function(){
                                        callback(value.length < 11);
                                        if (value.length > 10) {
                                            alert('more than 10 characters!');
                                        }
                                    }, 1000)
    
                                }
                                "
                )
        
        })
        
        
        observeEvent(input$saveButton, {
            invalid_values <-
                modified_data()$`Project Name`[nchar(modified_data()$`Project Name`) > 20]
            
            if (length(invalid_values) == 0) {
                saved_data <- hot_to_r(input$table)
                write.csv(saved_data,
                          file = "saved_project_data.csv",
                          row.names = FALSE)
                showModal(
                    modalDialog(
                        title = "Success",
                        "Data has been saved to 'saved_project_data.csv'.",
                        easyClose = TRUE
                    )
                )
            } else {
                showModal(modalDialog(
                    title = "Warning",
                    "DATA HAS NOT BEEN SAVED",
                    easyClose = TRUE
                ))
                
            }
        })
    }
    
    shinyApp(ui, server)