Drag and drop carousels in Orchard CMS

I’ve been enjoying my baptism of fire into the Orchard CMS recently. Here’s how I implemented owl carousel into it.

I read quite a few articles on this before embarking and went through quite a few iterations. The most flexible and easiest to implement I found was owl carousel, which is an excellent plugin with a wide variety of config options.

I first tried implementing them using this article as a guide. I found this way to be a bit long-winded though. You need to create each carousel item as a content item, then create a query that pulls those items together, then create a projection that shows the query, then add that to a page. Quite a few steps and not very flexible.

Playing with the layout module in Orchard, it seemed that if I could configure the output of the layout views, I could create a carousel that would allow me to define as many items as I wanted in one page, with as much rich content as necessary and then simply drop that on to a page.

Using layout

I wanted to keep things as simple as possible, so the solution I came up with means that the carousel is created as a content item, and this can then just be added to the layout of another page.

The code for the carousel is this…

  //migrations.cs
  ContentDefinitionManager.AlterPartDefinition("CarouselContentPart", b =>
  b
  .WithField("Theme", cfg =>
      cfg.OfType("EnumerationField")
          .WithSetting("EnumerationFieldSettings.Hint", "Carousel 1 - Pagination and navigation above items; Carousel 2 - Pagination numbers and navigation above items; Carousel 3 - Navigation vertically centred, No pagination; Carousel 4 - Navigation vertically centred, pagination underneath")
          .WithSetting("EnumerationFieldSettings.Options",
              string.Join(Environment.NewLine,
                  new[] { "carousel--1", "carousel--2", "carousel--3", "carousel--4" }))
          .WithDisplayName("Theme"))
  .WithField("ItemsPerPage", cfg =>
      cfg.OfType("NumericField")
          .WithSetting("NumericFieldSettings.Hint", "Enter the number of items to show")
          .WithSetting("NumericFieldSettings.Required", "true")
          .WithDisplayName("Items per page"))
  );

  ContentDefinitionManager.AlterTypeDefinition("CarouselContent", builder =>
    builder
    .DisplayedAs("Carousel Content")
    .WithPart("TitlePart")
    .WithPart("CommonPart", p => p
        .WithSetting("DateEditorSettings.ShowDateEditor", "True"))
    .WithPart("IdentityPart")
    .WithPart("LayoutPart")
    .WithPart("CarouselContentPart")
    .Creatable()
    .Listable()
    .Securable()
    );

This is a content type and part that contains simple configuration. The user can select how many items to show per page and what theme the carousel should be. It was decided that for end users, we would just give them 4 different flavours of carousel rather than allowing them to configure everything.

Since the CarouselContent content type contains a Layout part, the carousel items can just be added as grids in the layout. Inside each grid, any number of rows, columns and elements can be added, making this solution very flexible. If its a simple image that’s needed, these can be directly dropped on to the canvas.

carousel-1 For this kind of carousel, each item in the carousel needs to be grid. Inside each grid, the layout can be as simple or complex as needed.

carousel-2 For this kind of carousel, all that is needed are image elements.

Outputting the carousel

To actually pick up these config values, I copied the standard layout modules’ canvas view and added a bit.

//Views/Elements/Canvas.cshtml
if (Model.ContentItem.CarouselContentPart != null)
{
    if(tagBuilder == null)
    {
        tagBuilder = new OrchardTagBuilder("div");
    }

    var itemsPerPage = Model.ContentItem.CarouselContentPart.ItemsPerPage.Value;
    var theme = Model.ContentItem.CarouselContentPart.Theme.Value;
    tagBuilder.MergeAttribute("data-carousel-items", itemsPerPage.ToString());
    tagBuilder.AddCssClass("owl-carousel");
    tagBuilder.AddCssClass(theme);
}

This again is pretty simple. All it does it output some classes and data attributes on the canvas element. – It adds a data attribute which is picked up by javascript when the owl carousel is initialised – It adds a class of ‘owl-carousel’ to the main div, which is needed by the plugin – It adds a class based on the theme that was selected

That’s it, the rest is handled by javascript.

The javascript

Again, there’s nothing that complicated here, the script just loops through each carousel, picks up the config and initialises the carousel based on that.

$('.owl-carousel').each(function () {
  var self = $(this),
    items = self.attr('data-carousel-items') || 1;
  config = {
    items: items
  };

  if (self.hasClass('carousel--2')){
    $.extend(config, {
      paginationNumbers: true
    });
  }

  if (self.hasClass('carousel--3')){
    $.extend(config, {
      paginationNumbers: false,
      pagination: false
    });
  }
  self.owlCarousel(config);
});

So its just picking up the data attributes and setting some config values. Hopefully, its pretty obvious how to make the pagination and navigation controls configurable via the Orchard back office.

Conclusion

This solution allows very flexible, drag and drop carousels that can be easily configured and added to other pages. Since they exist as separate content items, they can also be added to different pages easily. And each item in the carousel can be as simple or complex as necessary without having to specifically define any fields other than the layout part.

Leave a Reply