Paragraphs are one of the powerful module in Drupal paradigm, it supports nesting feature and empowers developer with the most dynamic and flexible experience. I have used nested Paragraphs to build an Owl Carousel, where outer Paragraph is used as Carousel Container and the Inner Paragraph is used as Carousel Cards.
I have tried to implement two type of Owl Carousel, One Wide Image Carousel and Multiple Image Card Slider Carousel, both were implemented using same nested Paragraph distinguished with a custom field called field_carousel_type.
In the very beginning, get the Owl Carousel CSS and JS file and attach it through custom theme's libraries.yml file, the content of your custom theme's [MYTHEME].libraries.yml file may look like
global-styling:
css:
theme:
css/main.css: {}
css/owl.carousel.min.css: {}
css/owl.theme.default.min.css: {}
"//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css": {type: external, minified: true}
js:
js/jquery-ui.min.js: {}
js/owl.carousel.min.js: {}
js/my-custom.js: {}
dependencies:
- core/jquery
The next step is to create a paragraph type "carousel", this will act as a Carousel Container and and will have a custom select field "field_carousel_type" this will display carousel based on selected type, and it will have an entity reference field to another paragraph type "carousel_card", this paragraph type have an Imagefield, URL field.
This is the preprocess function for the paragraph used as carousel container.
function [YOURTHEME]_preprocess_paragraph__carousel(&$variables) {
$paragraph = $variables['paragraph'];
$type = $paragraph->get("field_carousel_type");
$type = $type->value;
$variables['type'] = $type;
}
This is the template file code for paragraph used as carousel container, you can clearly see that "field_carousel_type" value has been used to distinguish a carousel based on its type i.e. owl-carousel--{{ type }}
If the carousel type is "hero" it will have a class owl-carousel--hero
and if a carousel type is "featured" it will have a class owl-carousel--featured
{% block paragraph %}
<div class="rc rc--full">
<div class="owl-carousel owl-carousel--{{ type }} owl-theme">
{{ content }}
</div>
</div>
{% endblock paragraph %}
Next we have to adjust carousel card paragraph type by custom handling through preprocess function in [MYTHEME].theme file. The custom handling is required because there is a slight difference between two type of carousel.
function [YOURTHEME]_preprocess_paragraph__carousel_card(&$variables) {
$paragraph = $variables['paragraph'];
$parent_paragraph = $paragraph->getParentEntity();
$carousel_type = $parent_paragraph->get("field_carousel_type");
$featured = FALSE;
if ($carousel_type == "featured") {
$featured = TRUE;
}
$variables['featured'] = $featured;
$cta = $paragraph->get("field_cta");
$cta = $cta->getValue();
if ($cta) {
$url = Url::fromUri($cta[0]['uri'])->toString();
}
$variables['url'] = $url;
}
This is the template file for paragraph carousel_card.
{% block paragraph %}
<div>
<a href="{{ url }}" title="">
{% if featured %}
{{ content|without('field_cta') }}
{% else %}
<article class="slide-content">
{{ content|without('field_cta') }}
</article>
{% endif %}
</a>
</div>
{% endblock paragraph %}
Finally, when all this has been setup, we need to trigger the different carousel in our custom JS file, which has been attached in [MYTHEME].libraries.yml file.
/**
* @file
* MYTHEME Custom JS File, Here Site Custom JS code resides.
*/
(function ($) {
$( document ).ready(function() {
// owl carousel
$(".owl-carousel--hero").owlCarousel({
items: 1,
});
var fixOwlCarousel = function() {
stage = $('.owl-stage');
stage.width(stage.width() * 2);
}
var refreshFeatured = function() {
$(".owl-carousel--featured").trigger('refresh.owl.carousel');
}
var featured_carousel = $(".owl-carousel--featured").owlCarousel({
stagePadding: 100,
autoWidth: true,
loop: true,
margin:30,
dots: false,
center: true,
nav:true,
onInitialized: fixOwlCarousel,
onRefreshed: fixOwlCarousel,
onResized: refreshFeatured,
navText : ['<img src="/themes/custom/mytheme/img/ui/btn-previous.png">','<img src="/themes/custom/mytheme/img/ui/btn-next.png">']
});
var gallery_carousel = $(".owl-carousel--gallery").owlCarousel({
autoWidth: true,
nav:true,
loop: false,
margin: 30,
dots: false,
items: 2,
touchDrag: false,
mouseDrag: false,
onInitialized: fixOwlCarousel,
onRefreshed: fixOwlCarousel,
navText : ['<i class="fa fa-angle-left" aria-hidden="true"></i>','<i class="fa fa-angle-right" aria-hidden="true"></i>']
});
$(".owl-carousel--gallery .owl-item img").click(function( e ) {
e.preventDefault();
var src = $(this).data("img-full");
$("#gallery__img-selected").fadeOut(400,function(){
$(this).fadeIn(400)[0].src = src;
});
});
});
})(jQuery);