19 Dec 2017
Nested content is a list editing property editor for Umbraco 7+. It is similar to Archetype, but not as full featured. It's more stripped back and simple which I think is the reason why it has been included in Umbraco Core since 7.7
Not only is it pleasant for the editor to use, it is also pleasant to code with, because you are essentially just coding against IPublishedContent items.
Here is a demo site which uses a starter kit I created. That starter kit has a Carousel on the home page which is managed using Nested Content and is built using Bootstrap.
Nested Content allows you to use normal Umbraco document types as items in a list.
Here is what the document type will look like
And here is what it will look like when it is used in the home page.
As nested content uses normal Umbraco document types, it also means that we can use document type composition.
This isn't a requirement but it is beneficial. Consider this example.
Our carousel slide will have the following properties:
This is for our Main Carousel, but we may want a different carousel with similar properties, maybe it has no Subtitle, Image or Link.
With composition, we can create these in separate document types to allow us to compose the Nested Content document type.
Now we know what controls we will need on our Nested Content document type, we need to create our composition document types. I like to put doc types used for composition in their own Compositions folder.
Remember you don't have to do it like this, you can just create one document type called 'Carousel Slide' and add all of these properties to it. We are only doing it separately for document type composition. Notice I put them all on a tab called Content.
Now we have created our document types to be used in the carousel slide, we can pick them using Composition. This document type that we create now, will be what we use with the Nested Content data type.
Click on the Developer tab in the left menu.
Click on the 3 dots next to Data Types
Choose New data type.
{{umbracoNaviHide == 1 ? '[Disabled] ' : ''}}{{slideTitle}}The above bit of Angular will change the label for the item in the list. If it has Disabled ticked it will have [Disabled] in front of the name of the item.
Then click on Save
Now we have our Nested Content Document Type, we need to use it somewhere. We can either use Composition again, or we can add the property straight to the document type for the home page or whichever it will be used on.
Now we have our property set up and working, we need to add some content.
Go to the page where you added the property, mine is the Home Page.
Click on the Plus symbol and start entering data for the fields.
Edit: You can edit the item by clicking on it to open it out first, then you can just start editing the values.
Re-order: You can re-order the items by dragging the crosshair icon on the item and moving it up or down.
Delete: You can delete the item by clicking on the delete icon.
Disable: Because we added the Disable tick box we can disable an item by ticking this box.
Create a partial called "_MainCarousel.cshtml"
From the Template where you want to render the carousel, add this code:
Notice how easy it is to get the value of the Nested Content property and see that it returns an IEnumerable<IPublishedContent>
@inherits UmbracoViewPage @using Umbraco.Web.Models @{ string carouselId = "mainCarousel"; IEnumerable<IPublishedContent> carousel = Umbraco.AssignedContentItem.GetPropertyValue<IEnumerable<IPublishedContent>>(carouselId); } @if (carousel != null && carousel.Any()) { <div class="carousel slide" data-ride="carousel" id="@carouselId"> <div class="carousel-inner" role="listbox"> @{ int slideCount = 0; foreach (IPublishedContent slide in carousel.Where(x => x.IsVisible())) { string title = slide.GetPropertyValue<string>("slideTitle"); string subtitle = slide.HasValue("slideSubtitle") ? slide.GetPropertyValue<string>("slideSubtitle") : ""; string imageUrl = slide.HasValue("slideImage") ? slide.GetPropertyValue<IPublishedContent>("slideImage").Url : "/img/carousel.jpg"; IEnumerable<RelatedLink> links = slide.GetPropertyValue<IEnumerable<RelatedLink>>("slideLink"); RelatedLink link = links != null ? links.FirstOrDefault() : null; <div class="item @(slideCount == 0 ? "active" : "")"> <div class="jumbotron carousel-hero" style="background-image:url('@(imageUrl)');"> <h1 class="hero-title">@title</h1> <p class="hero-subtitle">@subtitle</p> <p><a class="btn btn-primary btn-lg hero-button" role="button" target="@(link.NewWindow ? "_blank" : null)" href="@link.Link">@link.Caption</a></p> </div> </div> slideCount++; } } </div> <div> <a class="left carousel-control" href="#@carouselId" role="button" data-slide="prev"><i class="glyphicon glyphicon-chevron-left"></i><span class="sr-only">Previous</span></a> <a class="right carousel-control" href="#@carouselId" role="button" data-slide="next"><i class="glyphicon glyphicon-chevron-right"></i><span class="sr-only">Next</span></a> </div> <ol class="carousel-indicators"> @for(int i = 0; i < slideCount; i++) { <li data-target="#@carouselId" data-slide-to="@i" class="@(i == 0 ? "active" : null)"></li> } </ol> </div> }
Nested content items are treated as IPublishedContent so you can get values from them as you would any other document type. This makes it very easy to work with.
In the foreach loop, you will see I added a condition to say .Where(x => x.IsVisible())
This checks the Disabled property (umbracoNaviHide) and only shows the item if that value does not equal '1'.
If you remember the label value for the Nested Content item, we set it to be:
{{umbracoNaviHide == 1 ? '[Disabled] ' : ''}}{{slideTitle}}
This uses the same logic.
Here is an example template for you to see what is needed for this to work:
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap-theme.min.css"> </head> <body> @{ Html.RenderPartial("SiteLayout/_MainCarousel"); } @RenderBody() <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> </body> </html>
It seems like a lot now that I've written it out, but the way you get the property values is a lot simpler than it was for Archetype, although Archetype had more functionality.
If you're struggling to follow this and work best with an example already in place, then download my CodeShare Starter Kit and install it on a fresh install of Umbraco 7.7+. You can even install it from the back office in the packages library.
If you want to come back to this article later, I've created some short and memorable links for you, which all point to this page:
http://www.codeshare.co.uk/nestedcontent