1. Home
  2. Blog
  3. 2019
  4. An Umbraco 8 Recipe - Nested content in a Grid tutorial

An Umbraco 8 recipe for a video carousel

Blog video carousel

A video carousel, using nested content in the grid editor

Umbraco is an uber-powerful CMS, but it can be hard to get your head around. It's like having a kitchen full of gadgets and ingredients, but without a cookery book (or years of experience) you can't always get great results.

This recipe is the results of a few experiments with ingredients and quantities to get the perfect bake. Follow along, or at least get a few hints at how to put things together.

Versions

Most documentation about implementing Umbraco starts with a Google. Various blogs, our.umbraco forum posts and good old StackOverflow are where we get most of the clues about how to use Umbraco. But there's always a game in getting information about the right version. Things change so much between v7, v8 and even back to v4 you have to be careful not to follow old fashioned advice. So to be clear, this works for me, in Sept 2019, using Umbraco 8.1 and deploying to Umbraco Cloud. It might work with other older versions, it will undoubtedly be superseded by a better approach in the years to come.

Packages and Plugins

Again, third party code does go out of date, and sometimes functionality moves into Umbraco Core. I know there are better things than the Grid in the development pipeline, but for now - this stuff works and you can build production websites with it and that's the main test.

I'll be using the following ingredients in this recipe, you can copy them or substitute your own alternatives if perhaps your clients have special dietary requirements. I haven't done any special hacks - nothing genetically modified either.

  • OWL Carousel 2. This is the jquery plugin that turns our html output on the public website into a slidey swipey carousel experience.
  • OEmbed Picker Property Editor - This is a neat single-purpose package (with a big untidy name) that helps content editors turn a Youtube or Vimeo url into a piece of content that can sit in an Umbraco document. A useful tool for using hosted video.
  • Doc Type Grid Editor - This clever appliance lets you put different document types into the Grid. It makes the content editing experience lovely and smooth for your editors, you just need to configure it right to work for you.

Here's one I made earlier:

As you can see the editor experience is straightforward.  Nice and simple, but very flexible because our Video Carousel component is available in a grid - which means it can be used in any position in the page and it can be wrapped up with different styles.

Ingredients

  1. A video - this is an embedded iframe from Youtube (other hosting services are available) and uses the OEmbed Picker Property Editor package to help an editor put it into Umbraco.  You will want more than one to make it worth having a carousel.

  2. A carousel item - this a doc type (Element) - containing a title and a video. Both bits of data are used together to make a single slide in the carousel

  3. A nested content item. This is a data type. Nested content allows you to have a list of several documents in one - I am using it to wrap up multiple slides into a single set of data for our carousel object.

  4. A video carousel container - a doc type (also an Element) - this contains a property of type Nested content. (aka an instance of the nested content item data type - pay attention at the back!). Essentially this turns the carousel data type back into a doc type, so it can be inserted into the grid. But it's also a container that could be for titling, styling or adding in some control options.

  5.  An entry in the grid, where the video carousel is inserted. This magic is provided by the DocTypeGridEditor package. This also links in the View that will render the video carousel (think of it as a hardcoded doc type template - because element types don't have templates). This View will be a file named after the alias of the container doctype, and will live under the views directory. e.g. /Views/Partials/VideoCarouselContainer.cshtml

    The big advantage of having the nested content element in the grid instead of directly in the page template is all sorts of flexibility about where to put it in the document and how to style and position the output.

  6. The jquery that turns the final output into a functioning carousel. This is added dynamically by the site because there is no telling where editors may end up needing it, and you want the end result to "just work".  Although the required libraries are added as scripts in the page header so they are always available.

  7. Coffee. Probably two cups to do this right. Flavour to taste and add to the mix as needed.

Method

1. Setup

I'm using Umbraco 8.1.4 for this walkthrough. It's an Umbraco Cloud solution, using Visual Studio 2019 for development, and uses the most excellent Models Builder Extension in order to use strongly typed content models. I'm using gulp to compile sass, minify js and make nice clientside distributions of all the necessary bits that make a modern web application. I'm not going to get distracted by how to configure any of that, many other valid approaches and opinions are available.

2. Teach Umbraco how to embed videos nicely

This involves using Dave Woestenborghs' most excellent package OEmbed Picker - simply follow the installation instructions on the packet.  Then you need to create your data type using this property editor:

3. Define a Carousel Slide document type

Each slide has a video and an optional bit of text as a title. These are put together as a document type.  The video element uses the Embedded Media data type that was defined earlier:

Gotcha number one here - ensure you create this document type without any template (otherwise they will be orphaned and break Umbraco Deploy when pushing to the cloud - true story) and that you tick the "Is an Element Type" box under the Permissions menu.  This means it will become available for use at the next stage.

4. Add the slides into a Nested Content collection

Nested content is the native way of adding collections of more than one item into a document in Umbraco 8.  You define a data type for your nested content, which in turn could be used by one or more document types.  It looks like this:

We are steadily building up the layers, using the different elements in different ways to create the components. Sometimes it's good to experiment first, then make your final set of data types and documents with only the bits you know you need and find meaningful names at each stage to make it easier to maintain and reuse.

5. Define the carousel document type, containing the slides

Now we are the point where we can create a document type to represent the entire carousel.

Again this has to be an element type. (I tried to find a handy link to documentation about the Element Type switch - but I can't find any!)  Element types mean the content you create does not have a URL, a template, or appear in the content tree. The content only exists as part of another bigger document. Which is useful in this recipe because we are creating our carousel within the grid of another web page. 

Anyway, my document type looks like this:

6. Install the Document Type Grid Editor (DTGE) package

One of those packages that you can't believe is not core functionality, adding DTGE is a straight forward nuget installation, but you need to do some configuration. There is a useful Developers Guide that gives useful background to what I'm doing here.

The most important place to start is the configuration in this file:

~/App_Plugins/DocTypeGridEditor/package.manifest

This bit of happy json defines the document types that you are allowing editors to create in a grid. Here's the relevant snippet:  

{
  "gridEditors": [
    {
      "name": "Video Carousel",
      "alias": "videoCarousel",
      "view": "/App_Plugins/DocTypeGridEditor/Views/doctypegrideditor.html",
      "render": "/App_Plugins/DocTypeGridEditor/Render/DocTypeGridEditor.cshtml",
      "icon": "icon-video",
      "config": {
        "allowedDocTypes": [ "videoCarouselContainer" ],
        "nameTemplate": "",
        "enablePreview": true,
        "largeDialog": true,
        "viewPath": "/Views/Partials/Grid/Editors/DocTypeGridEditor/",
        "previewViewPath": "/Views/Partials/Grid/Editors/DocTypeGridEditor/Previews/",
        "previewCssFilePath": "/App_Plugins/DocTypeGridEditor/css/preview-videoCarousel.css",
        "previewJsFilePath": ""
      }
    },
    {
      "name": "Collapsible Section",
      "alias": "collapsible",
...
}
]
}

 

Please note you can use the DTGE for several different document types, I've left in a bit about a collapsible section as a little tease.

You can experiment with most of the settings - names and icons are always important, but you need to save the file in Visual Studio, and save web.config for your dev server to notice the configuration changes before reloading your browser. The key setting is the list of allowedDocTypes - I've added in VideoCarouselContainer as the alias of my document type.

Another gotcha: the name of the allowed DocTypes is actually a prefix, and will match all doc types that start with this string. This caught me out when I had a VideoCarousel containing VideoCarouselItems - as it gave me a choice of what to add. Name things carefully!

7. Configure your Grid Layout to allow using the DTGE

The next bit of configuration is in the Grid Layout property editor Probably best to demonstrate this one:

The basic idea is that for your Grid document type, you need to go into the row configurations, then the column sections, and then tick the box next to the Video Carousel (this is the name/icon combination from the manifest file) to enable the new editor in the grid.

8. Make some content

All the parts are now in place to go into the content section of the web office and add in our first test carousel. Watch this little gif to show you what to click.

9. Preview!

Oh. Well that's another fine mess you've got me into Umbraco.

But at least there is a helpful error message here. The problem is that the VideoCarouselContainer is an element type - with no corresponding template to display the information. We need to create a View file which will be called with the VideoCarouselContainer model to render the page.

10. ViewCarouselContainer.chstml

I created the following file in the Views/Partials :

@inherits UmbracoViewPage<ContentModels.VideoCarouselContainer>
@using ContentModels = Umbraco.Web.PublishedModels;
<div class="video-carousel">
    @{foreach (var item in Model.Carousel)
        {
            <div class="item-video">
                @item.Video.EmbedCode
                <h4>@item.Title</h4>
            </div>
        }
    }
</div>

 

The magic of ModelsBuilder means my code is strongly typed - in other words Visual Studio Intellisense knows that my Model has a Carousel property which I can loop over, and each item has a Video property (of type OEmbedItem) which has the EmbedCode in it.

This is enough to give me some sensible shaped html. which is close enough to become a carousel ...

11. Just add javascript and css

To get the end result, I added in  OWL Carousel 2.  Follow the installation instructions, I added it to my gulp process as a required javascript file that gets added to the project distribution folder. 

We usually use a javascript module pattern for code on the page - there is a global array: init[] that we can push functions into from anywhere in the clientside rendered code. The master template is then responsible for executing each function in the init array in turn, after the dom and any code dependencies have been loaded by the browser. 

This makes it easy to add in the initialisation javascripts into the same view. The code is designed to be safe to add several times in case more than one carousel is added to the page.

My ViewCarouselContainer.chstml now looks like this:

@inherits UmbracoViewPage<ContentModels.VideoCarouselContainer>
@using ContentModels = Umbraco.Web.PublishedModels;
<div class="owl-carousel @("carousel" + Model.GetHashCode())">
    @{foreach (var item in Model.Carousel)
        {
            <div class="item-video">
                <a class="owl-video" href="@item.Video.Url"></a>
                <h4>@item.Title</h4>
            </div>
        }
    }
</div>

<script>
    init.push(function () {
        $('.@("carousel" + Model.GetHashCode())').owlCarousel({
            items: @Model.Carousel.Count(),
            video: true,
            autoWidth: true,
            margin: 15,
            videoHeight: @(Model.VideoHeight == 0 ? 197 : Model.VideoHeight),
            videoWidth: @(Model.VideoWidth == 0 ? 500 : Model.VideoWidth),
            center: @Model.CarouselCentre.ToString().ToLower(),
            @if (@Model.CarouselLoopItems) {
             @: loop: true, dots: false
            } else {
              @: dotsClass: 'video-carousel__dots', dotClass: 'carousel__dot'
            }
        });
    });
</script>

12. Just one more thing ...

The public side is fine, but there is one last tweak to improve the editor experience - creating a custom view for previewing the output within the grid editor.  Remember the DTGE package.manifest file?  This contains properties to reference in custom view, css and javascript for use in the preview.  I added in a slimmed down version of the videoCarouselContainer.cshtml from the public site - that has the loop to produce the blocks of content, and some basic styling to make the blocks look like videos.

This part may not win design awards, but at least the editors have an idea of what they have in their document.

Let's work together

We’d love to hear from you. Make our day.
All ideas welcome. We’ll soon let you know if we’re able to help.

Contact us