JohnCoene / cicerone

🏛️ Give tours of your Shiny apps
https://cicerone.john-coene.com
Other
187 stars 7 forks source link

Update input #13

Closed fmmattioni closed 4 years ago

fmmattioni commented 4 years ago

Hi John!

Thanks a lot for this package. I was previously using rintrojs and now that I am updating a shiny app, I decided to give cicerone a try. It is much easier to use, and makes the code cleaner!

I have one question: would it be possible to update an input once the guide reaches a specific input? For example, this is what I would do in rintrojs:


library(shiny)
library(rintrojs)

ui <- fluidPage(
  br(),
  br(),

  introjsUI(),

  shinyWidgets::switchInput(
    inputId = "demo_mode",
    size = "mini",
    onStatus = "success", 
    offStatus = "danger"
  ),

  numericInput(
    inputId = "input_1", 
    label = "Label numeric input:", 
    value = 0
  )
)

server <- function(input, output, session){

  steps_intro <- reactive(
    data.frame(
      element = "#input_1",
      intro = "Here you can choose a number."
    )
  )

  observe({
    req(input$demo_mode)

    rintrojs::introjs(
      session,
      options = list(steps = steps_intro()),
      events = list(
        onchange = I(
          "if (this._currentStep==0) {
          $('#input_1').val(50);
          Shiny.onInputChange('input_1', 50);
          }
          "
        ))
    )
  })
}

shinyApp(ui, server)

Thanks in advance!

JohnCoene commented 4 years ago

Ah, had not thought of that, I've added the on_highlighted argument to run an arbitrary JavaScript function when the step is highlighted.

library(shiny)
library(cicerone)

guide <- Cicerone$
  new(id = "homeGuide")$
  step(
    "step1",
    "Hello",
    "This is the first step"
  )$
  step(
    "input1",
    "Text",
    "Input has changed",
    on_highlighted = "function(element){
      $('#input1').val(50);
    }"
  )

ui <- fluidPage(
  use_cicerone(),
  h1("Title", id = "step1"),
  numericInput(
    inputId = "input1", 
    label = "Label numeric input:", 
    value = 0
  )
)

server <- function(input, output, session){

  guide$init()$start()

}

shinyApp(ui, server)

Does this solve the issue?

EDIT: for reference if anyone lands on this issue, an example is here

fmmattioni commented 4 years ago

Hi, John!

That is great! Thank you so much for looking into it so quickly!

The function is working great! I love it!

Also, for future reference, I guess you would also need to add Shiny.onInputChange('input1', 50); to the example because otherwise the input wouldn't change in the background. What do you think?

Thanks again!

JohnCoene commented 4 years ago

Ah yes, this does not change the value server side.

I changed it the function below which though less readable is probably more robust: using shiny's built-in receiveMessage handler (used for update*Input) which updates UI and server at the same time.

function(element){
    var el = document.getElementById('input1');
    Shiny.inputBindings.bindingNames['shiny.textInput'].binding.receiveMessage(el, {value: 20})
}
fmmattioni commented 4 years ago

This is great, John! I did not know about receiveMessage. Thanks again!