JohnCoene / cicerone

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

'on_highlighted' argument is triggered at the start of the tour #15

Closed thiagomaf closed 3 years ago

thiagomaf commented 3 years ago

I am running a Cicerone tour as a tutorial of my shinydashboard app UI. The idea is to walk the user thru the various inputs in the interface. Some of these inputs are present inside boxes which are presumably collapsed at the start of the tour, my goal is to use the 'on_highlighted' argument to trigger a shinysj toggle command at a given specific step().

The toggle command works fine independently. The Cicerone tour works fine independently. But the shinyjs is not trigerred at the specific step() but rather at the start of the tour (i.e. before first step()).

Below an example:

library(shiny)
library(shinydashboard)
library(cicerone)
library(shinyjs)

jscode <- "
shinyjs.collapse = function(boxid) {
$('#' + boxid).closest('.box').find('[data-widget=collapse]').click();
}
"

ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody(
    useShinyjs(),
    extendShinyjs(text = jscode, functions = "collapse"),

    use_cicerone(),

    div(
      box(
        textInput(
          inputId     = "text1",
          label       = "Text 1",
          value       = "",
          placeholder = "Text 1"
        ),

        textInput(
          inputId     = "text2",
          label       = "Text 2",
          value       = "",
          placeholder = "Text 2"
        ),

        textInput(
          inputId     = "text3",
          label       = "Text 3",
          value       = "",
          placeholder = "Text 3"
        ),
      )
    ),

    box(
      id          = "super_box",
      title       = "Expandable box",
      solidHeader = TRUE,
      collapsible = TRUE,
      collapsed   = TRUE,

      "Stuff inside the box!",
      textInput(
        inputId     = "text4",
        label       = "Text 4",
        value       = "",
        placeholder = "Text 4"
      )
    ),

    actionButton(inputId = "tutorial", label = "Tutorial"),
    actionButton(inputId = "expand",   label = "Expand")
  )
)

server <- function(input, output) {
  observeEvent(input$expand, {
    js$collapse("super_box")
  })

  observeEvent(input$tutorial, {
    Cicerone$
      new()$
      step(
        el          = "text1",
        title       = "Text 1",
        class       = "popover",
        description = "Info 1"
      )$
      step(
        el          = "text2",
        title       = "Text 2",
        class       = "popover",
        description = "Info 2"
      )$
      step(
        el          = "text3",
        title       = "Text 3",
        class       = "popover",
        description = "Info 3"
      )$
      step(
        el          = "text4",
        title       = "Expand box",
        class       = "popover",
        description = "Is it expanded?",
        on_highlighted = js$collapse("super_box")
      )$
      init()$
      start()
  })
}

shinyApp(ui, server)
etiennebacher commented 3 years ago

I have an error when I run your code, I think you forgot to put functions = "collapse" in extendShinyjs(). But this doesn't solve your problem

thiagomaf commented 3 years ago

This actually puzzeld me.

In my working app it also complained about it and I had to include it as you said. But in this example it didn't complain about it and would only run the js code if the 'functions' argument was NULL.

Just in case I have included it again as suggested.

JohnCoene commented 3 years ago

I found the issue(s). There are multiple things at play here.

First, the on_highlighted argument takes a function, the documentation read "arbitrary piece of JavaScript code," this is not entirely true as it must be a function. Apologies.

Second, on_highlighted does not work here as this function is actually executed after the element is highlighted but said element cannot be highlighted because it is collapsed.

Third, I'm not familiar with shinyjs' extend: the issue is that it not being a function it was executed when cicerone was initialised: wrap it in a function and it works.

I have thus added two arguments to pass to steps:

  1. on_highlight_started
  2. on_next

Both take JavaScript function (R character strings), the first is triggered just before the element is highlighted, the second is triggered when the next button is clicked.

This will require installing the github version.

install.packages("remotes")
remotes::install_github("JohnCoene/cicerone")

The code below works, the only change is using on_highlight_started and wrapping your JavaScript code in a function.

library(shiny)
library(shinydashboard)
library(cicerone)
library(shinyjs)

jscode <- "
shinyjs.collapse = function(boxid) {
  $('#' + boxid).closest('.box').find('[data-widget=collapse]').click();
}
"

ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody(
    useShinyjs(),
    extendShinyjs(text = jscode, functions = "collapse"),

    use_cicerone(),

    div(
      box(
        textInput(
          inputId     = "text1",
          label       = "Text 1",
          value       = "",
          placeholder = "Text 1"
        ),

        textInput(
          inputId     = "text2",
          label       = "Text 2",
          value       = "",
          placeholder = "Text 2"
        ),

        textInput(
          inputId     = "text3",
          label       = "Text 3",
          value       = "",
          placeholder = "Text 3"
        ),
      )
    ),

    box(
      id          = "super_box",
      title       = "Expandable box",
      solidHeader = TRUE,
      collapsible = TRUE,
      collapsed   = TRUE,

      "Stuff inside the box!",
      textInput(
        inputId     = "text4",
        label       = "Text 4",
        value       = "",
        placeholder = "Text 4"
      )
    ),

    actionButton(inputId = "tutorial", label = "Tutorial"),
    actionButton(inputId = "expand",   label = "Expand")
  )
)

server <- function(input, output) {
  observeEvent(input$expand, {
    js$collapse("super_box")
  })

  observeEvent(input$tutorial, {
    Cicerone$
      new()$
      step(
        el          = "text1",
        title       = "Text 1",
        class       = "popover",
        description = "Info 1"
      )$
      step(
        el          = "text2",
        title       = "Text 2",
        class       = "popover",
        description = "Info 2"
      )$
      step(
        el          = "text3",
        title       = "Text 3",
        class       = "popover",
        description = "Info 3"
      )$
      step(
        el          = "text4",
        title       = "Expand box",
        class       = "popover",
        description = "Is it expanded?",
        on_highlight_started = "function(){
          $('#super_box').closest('.box').find('[data-widget=collapse]').click();
        }"
      )$
      init()$
      start()
  })
}

shinyApp(ui, server)
JohnCoene commented 3 years ago

I'll assume this fixed the issue and close this, feel free to reopen if it is not the case.

thiagomaf commented 3 years ago

Sorry man, crazy week. Could not test it yet but I will let you know soon if I face any issue.

Thanks for that.

JohnCoene commented 3 years ago

No worries

thiagomaf commented 3 years ago

Worked perfectly - both the 'on_highlight_started' and the 'on_next'.

Many thanks again.