bretauv
bretauv

Reputation: 8557

Link JavaScript code to an R Shiny widget

Summary: I would like to adapt a JavaScript library (namely OwlCarousel2) in R, and more precisely in R Shiny. I have made several steps so far, but I can't find a way to append the JS script necessary at the end of the HTML structure (just before the end of body).


OwlCarousel2 is a library that allows to create cards and to make them slide. See here for more details.

What I've done so far:

I made three functions: owl_carousel_item() to create cards, owl_carousel() to embed the cards into a div with the class slider owl-carousel, and html_dependency_owlcarousel() to include the dependencies.

html_dependency_owlcarousel <- function() {
  htmltools::htmlDependency(
    name = "owl.carousel",
    version = "2.3.4",
    package = "shinymisc",
    src = "htmlwidgets/owl_carousel",
    script = c("owl.carousel.min.js", "owl.carousel.js"),
    stylesheet = c("owl.carousel.min.css", "style.css"),
    all_files = FALSE
  )
}

owl_carousel <- function(id, ...) {

  tag <- htmltools::tags$div(
    id = id,
    class = "slider owl-carousel",
    ...
  )

  htmltools::tagList(
    tag,
    html_dependency_owlcarousel()
  )
}

owl_carousel_item <- function(title, subtitle, content = NULL, button_text = NULL, width = "300px") {

  if (!is.null(button_text))
    button <- shiny::tags$div(class = "btn", value = button_text)
  else
    button <- NULL

  shiny::tags$div(
    class = "card",
    style = paste0("width: ", width),
    shiny::tags$div(class = "img"),
    shiny::tags$div(
      class = "content",
      shiny::tags$div(class = "title", title),
      shiny::tags$div(class = "sub-title", subtitle),
      shiny::tags$p(content),
      button
    )
  )

}

With this code (and the dependencies), I produce an app that has an HTML structure almost equivalent to the one I could create outside the package environment: it displays the cards, but they don't slide. The thing that is missing is the <script> that should be at the bottom of this structure, just before the end of <body>. This is why the cards don't slide.

I tried to apply the method described in this chapter of the book previously mentioned, but not success because I couldn't make htmlwidgets::createWidget() work with my tag.

Therefore, my question is: how can I place the following script at the end of the HTML structure?

$(".slider").owlCarousel({
    loop: true,
    autoplay: true,
    autoplayTimeout: 2000, //2000ms = 2s;
    autoplayHoverPause: true,
  });

Keep in mind that these options should be editable through the function owl_carousel() (so just pasting this at the end of tag in owl_carousel() is not enough).

I know that this must not be very clear, so here's the link to the repo containing what I've made so far.

Note: this should be less hard than for other widgets. Here's there is no *Output or render* functions, no data, just a function to embed boxes and make them slide.

Edit: some code to test that it works (it should display two cards and an animation):

library(shiny)
library(fullPage)

ui <- fullPage(
  menu = c("Section 1" = "section1"),
  pageSection(
    menu = "section1",
    owl_carousel(
      id = "test",
      owl_carousel_item(
        title = "test1",
        subtitle = "subtitle1",
        content = "this is a test"
      ),
      owl_carousel_item(
        title = "test2", 
        subtitle = "subtitle2", 
        content = "this is a test", 
        button_text = "button to click"
      )
    )
  )
)

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

shinyApp(ui, server)

Upvotes: 4

Views: 262

Answers (1)

Abdessabour Mtk
Abdessabour Mtk

Reputation: 3888

The solution was moving the owl_carousel.js into inst/htmlwidgets and modifying the renderValue function to include the provided jQuery code.

renderValue: function(x) {

  // TODO: code to render the widget, e.g.
  el.innerHTML = x.message;

  $(".slider").owlCarousel({
    loop: true,
    autoplay: true,
    autoplayTimeout: 2000, //2000ms = 2s;
    autoplayHoverPause: true,
  })

}

And changing the return value of the owl_carousel function to :

owl_carousel <- function(id, ..., width = "100%", height = "400px") {

  tag <- htmltools::tags$div(
    id = id,
    class = "slider owl-carousel",
    ...
  )
  
  x <- list(message=as.character(htmltools::tagList(
    tag,
    html_dependency_owlcarousel()
  )))
  htmlwidgets::createWidget(
     name = 'owl_carousel',
     x,
     package = 'shinymisc'
   )
}

Edit For the css issue you haven't included style.css in the yaml:

dependencies:
 - name: jQuery
   version: 3.5.1
   src: htmlwidgets/jquery
   script: jquery.min.js
 - name: OwlCarousel2
   version: 2.3.4
   src: htmlwidgets/owl_carousel
   script: owl.carousel.min.js
   stylesheet:
    - owl.carousel.min.css
    - style.css

Result

Upvotes: 1

Related Questions