Reputation: 8557
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:
First of all, I checked that I could reproduce the expected behavior of this library only with HTML, CSS and JS, following this tutorial.
Then I tried to adapt this in R Shiny. Basically, I created functions embedding the raw HTML, I put the JS and CSS in www
, and I ran the app to be sure it worked. It did: the cards were displayed, and there was the slide behavior. But this was a bit messy so I decided to turn it into a package, so that I (and others) could re-use it more easily.
To transform this into a package, I used two sources:
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
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