Search code examples
rshinyshiny-reactivityshinywidgets

How to change knobInputs parameter (readOnly) in shiny with updateKnobInput?


I have a shiny app that uses knobInputs from shinywidgets. I need to change some of the parameters dynamically in the server. I know how to change the value of a knob using updateKnobInput, but I don't understand how to change the other parameters. Specifically, I need to set readOnly from FALSE to TRUE, when a certain thing is clicked by the user.

In the documentation of updateKnobInput it states: "options List of additional parameters to update, use knobInput's arguments." Unfortunately, I do not understand how to actually code this

Please see my example. When the user clicks the button, the knob's value should change from 50 to 15 (that works) and the knobs readOnly should change from FALSE to TRUE (that does not work).

library(shiny)
library(shinyWidgets)

ui <- fluidPage(
    knobInput("myknob", label = "My Knob", min = 0, max = 100, value = 50, readOnly = F),
    actionButton("changeknob", label = "Change the knob")
)


server <- function(input, output, session) {
    observeEvent(input$changeknob, {
        updateKnobInput(session, "myknob", value = 15, options = list(readOnly = T))
    })
}


shinyApp(ui = ui, server = server)

Thank you very much for your help!


Solution

  • After looking into the code of the widget, it seems to me that the API is buggy.

    • In principal the widget could receive a change in the readOnly attribute on the JavaScript side
    • However, this API is not implemented on the R side
    • Diving even further into the underlying jQuery Knob element it seems to me (but bear in mind that my JS is not that solid) that the readOnly attribute can be only set upon startup of the element.

    To make a longs tory short, in my opinion with the current implementation of both shinyWidgets::knobInput and the jQuery knob widget itself it is not possible to achieve it in the way you want.

    Thus, you need a workaround. You could re-render the widget based on the button press like in this example:

    library(shiny)
    library(shinyWidgets)
    
    ui <- fluidPage(
        uiOutput("knob_container"), 
        actionButton("changeknob", label = "Change the knob")
    )
    
    
    server <- function(input, output, session) {
        output$knob_container <- renderUI({
           was_pressed <- input$changeknob > 0
           knobInput("myknob", label = "My Knob", min = 0, max = 100, 
                     value = ifelse(was_pressed, 15, 50), readOnly = was_pressed)
        })
     }
    
    
    shinyApp(ui = ui, server = server)