1

Here are two numericInput fields whose total is shown in a third field. If I highlight all of the digits in Field A and press delete or space the field is left blank and the sum no longer works, because not all the elements to add are numbers.

How is it possible to have the field show "0" if:

  • All the digits are selected and either space or delete is pressed.
  • All the digits are deleted.

Also, even though it's a numeric field the keys "e", ".", and "+" are allowed. Can they be prevented from appearing?

library("shiny")
library("bslib")
library("shinyWidgets")

ui <- bootstrapPage(
  # https://bootswatch.com/journal/
  theme = bs_theme(version = 5, "font_scale" = 1.0), 
  div(class = "container-fluid",
      
      div(class = "row",
          div(class="col-4", 
              numericInputIcon(
                inputId = "a",
                label = "A",
                value = 10,
                min = 0,
                max = 9000,
                width = "160px",
                icon = list(NULL, per_month)
              ),
          ),
          div(class="col-4", 
              numericInputIcon(
                inputId = "b",
                label = "B",
                value = 255,
                min = 0,
                max = 9000,
                width = "160px",
                icon = list(NULL, per_month)
              ),
          ),
          div(class="col-4", 
              numericInputIcon(
                inputId = "total",
                label = "Total",
                value = 0,
                min = 0,
                max = 9000,
                width = "160px",
                icon = list(NULL, per_month)
              ),
          ),
      )
  )
)

server <- function(input, output, session) {
  observe({
    updateNumericInputIcon(
      session = session,
      inputId = "total",
      value = sum(c(input$a, input$b),na.rm=T)
    )
  })
  
  # This doesn't seem to work
  observe({
    if (!is.numeric(input$a)) {
      updateNumericInput(session, "a", 0)
    }
  })
}

shinyApp(ui = ui, server = server)
ixodid
  • 2,180
  • 1
  • 19
  • 46
  • Can you change `value = input$a + input$b` to `value = sum(c(input$a, input$b),na.rm=T)` – langtang Feb 22 '22 at 02:22
  • Regarding preventing characters in the numeric input fields, does this help:https://stackoverflow.com/questions/38246439/restrict-input-type-in-shiny-field – langtang Feb 22 '22 at 02:25
  • That's a partial solution. The sum field works when the other fields are blank. However, I think it would be clearer to display a "0" rather than have a blank field. – ixodid Feb 22 '22 at 02:26
  • I tried observe({ if (!is.numeric(input$a))... (see modified question) but couldn't get a zero to appear when I cleared the field. – ixodid Feb 22 '22 at 02:31

1 Answers1

2

Your above code uses updateNumericInput instead of updateNumericInputIcon. Also make sure to provide named parameters if you don't pass them in the expected order:

library("shiny")
library("bslib")
library("shinyWidgets")

ui <- bootstrapPage(
  # https://bootswatch.com/journal/
  theme = bs_theme(version = 5, "font_scale" = 1.0), 
  div(class = "container-fluid",
      
      div(class = "row",
          div(class="col-4", 
              numericInputIcon(
                inputId = "a",
                label = "A",
                value = 10,
                min = 0,
                max = 9000,
                width = "160px",
                icon = list(NULL, per_month)
              ),
          ),
          div(class="col-4", 
              numericInputIcon(
                inputId = "b",
                label = "B",
                value = 255,
                min = 0,
                max = 9000,
                width = "160px",
                icon = list(NULL, per_month)
              ),
          ),
          div(class="col-4", 
              numericInputIcon(
                inputId = "total",
                label = "Total",
                value = 0,
                min = 0,
                max = 9000,
                width = "160px",
                icon = list(NULL, per_month)
              ),
          ),
      )
  )
)

server <- function(input, output, session) {
  observe({
    freezeReactiveValue(input, "total")
    updateNumericInputIcon(
      session = session,
      inputId = "total",
      value = sum(c(input$a, input$b),na.rm=T)
    )
  })
  
  observe({
    if (!is.numeric(input$a)) {
      freezeReactiveValue(input, "a")
      updateNumericInputIcon(session, inputId = "a", value = 0)
    }
  })
}

shinyApp(ui = ui, server = server)

To avoid triggering reactives or outputs unnecessarily you should almost alway use freezeReactiveValue when using a update* function in . Please see this related chapter from Mastering Shiny.

On the long run I'd recommend using library(shinyvalidate).

ismirsehregal
  • 30,045
  • 5
  • 31
  • 78