rshinyrhandsontable

Why is the calculated column not updated after submitting values?


I have a data.table with following four columns:

col1 = as.numeric(0),
col2 = as.numeric(0),
col3 = as.numeric(0),
col4 = as.numeric(0)

In case of !is.na(df$col2) OR df$col2 != 0 col4 = col2 + col3 otherwise col4 = col1 + col3

In frames of a shiny app I have used a nested ifelse() statement to do this conditional calculation. In this regard I have tried the following two versions of code but col4 is not getting a result in either of cases.

Can someone show me a right approach?

I went through several SO questions but could not effectively figure out how to use their solutions in my case.

The first version of my code:

library(shiny)
library(shinydashboard)
library(rhandsontable)
library(data.table)

DF <- data.table(
  col1 = as.numeric(0),
  col2 = as.numeric(0),
  col3 = as.numeric(0),
  col4 = as.numeric(0),
  stringsAsFactors = FALSE
)

ui <- fluidPage(
  dashboardPage(
    dashboardHeader(),
    dashboardSidebar(        
      menuItem("Calculation", tabName = "calc")
    ),
    dashboardBody(
      tabItems(
        tabItem(tabName = "calc",
                rHandsontableOutput("table")
        )
      )
    )
  )
)

server = function(input, output, session) {
  
  data <- reactiveValues()
  
  observe({ data$df <- as.data.table(DF) })
  
  observeEvent(input$table, {
    data$df[[4]] <- ifelse(
      !is.na(data$df[[2]]) | data$df[[2]] != 0,
      data$df[[2]] + data$df[[3]],
      ifelse(
        data$df[[2]]==NA | data$df[[2]] == 0,
        data$df[[1]] + data$df[[3]],
        NULL
      )
    )
  })
  
  output$table <- renderRHandsontable({
    rhandsontable(data$df)
  })
}

shinyApp(ui, server)

The second version of my code:

library(shiny)
library(shinydashboard)
library(rhandsontable)
library(data.table)


DF <- data.table(
  col1 = as.numeric(0),
  col2 = as.numeric(0),
  col3 = as.numeric(0),
  col4 = as.numeric(0),
  stringsAsFactors = FALSE
)

ui <- fluidPage(
  dashboardPage(
    dashboardHeader(),
    dashboardSidebar(        
      menuItem("Calculation", tabName = "calc")
    ),
    dashboardBody(
      tabItems(
        tabItem(tabName = "calc",
                rHandsontableOutput("table")
        )
      )
    )
  )
)

server = function(input, output, session) {
  
  data <- reactiveValues()
  
  observe({ data$df <- as.data.table(DF) })
  
  output$table <- renderRHandsontable({
    data$df[, col4 := ifelse(!is.na(data$df[[2]]) | data$df[[2]] != 0,
                             data$df[[2]] + data$df[[3]],
                             ifelse(data$df[[2]]== NA | data$df[[2]] == 0,
                                    data$df[[1]] + data$df[[3]],
                                    NULL))]
    rhandsontable(data$df)
  })
}

shinyApp(ui, server)

Solution

  • The issue why col4 is not updated is that in your code the reactiveValue defined by data$df is once initialized to as.data.table(DF) (where DF is your initial data frame) and then never gets updated with the current user-submitted values from the RHandsontable. You can do this using hot_to_r as done below, i.e. data$df <- as.data.frame(hot_to_r(input$table)).

    Unrelated here, but your if condition does not make sense. If you say !is.na(df$col2) OR df$col2 != 0 and e.g. df$col2 is NA, then the or in the second part leads to NA which breaks the output in column 4. You may need & here or something else (below I used &, note that FALSE & NA evaluates to FALSE and FALSE | NA evaluates to NA).

    library(shiny)
    library(shinydashboard)
    library(rhandsontable)
    library(data.table)
    
    DF <- data.table(
      col1 = as.numeric(0),
      col2 = as.numeric(0),
      col3 = as.numeric(0),
      col4 = as.numeric(0),
      stringsAsFactors = FALSE
    )
    
    ui <- fluidPage(
      dashboardPage(
        dashboardHeader(),
        dashboardSidebar(        
          menuItem("Calculation", tabName = "calc")
        ),
        dashboardBody(
          tabItems(
            tabItem(tabName = "calc",
                    rHandsontableOutput("table")
            )
          )
        )
      )
    )
    
    server = function(input, output, session) {
      
      data <- reactiveValues(df = as.data.table(DF))
      
      observeEvent(input$table, {
        data$df <- as.data.frame(hot_to_r(input$table))
        
        data$df[[4]] <- ifelse(
          !is.na(data$df[[2]]) & data$df[[2]] != 0,
          data$df[[2]] + data$df[[3]],
          data$df[[1]] + data$df[[3]]
        )
      })
      
      output$table <- renderRHandsontable({
        rhandsontable(data$df)
      })
    }
    
    shinyApp(ui, server)