Last updated: Jan 04 2017

Area: Episerver CMS Applies to versions: 10 and higher
Other versions:

Preview rendering for blocks

This topic describes how to create a view and controller for previewing blocks in Episerver. The preview adds on-page editing functionality, and a realistic view of what the block will look like when added to content areas with different widths.

How it works

Shared blocks are rendered in the context of a page, for example inside a content area. Like pages, blocks can be edited in the all properties editing view, but to be able to preview and edit them in the on-page edit view, you can create a preview page used to render blocks in edit view. A block template is typically a partial template like a partial MVC controller, or a partial view. The rendering is using the built-in Preview tag in the EPiServer.Framework.Web namespace.

Creating a block preview template

In this example we created these components to build a preview that can be used for all blocks:

  • A block preview page type
  • A block edit page view model
  • A preview controller
  • A preview view

See Page types and templates, and Block types and templates, for information on how to create page types, controllers and views.

Block preview page type

Example: The block preview page type with a content area.

namespace MyEpiserverSite.Models.Pages
{
    public class PreviewBlock : PageData
    {
        public IContent PreviewContent { get; set; }
        public ContentArea ContentArea { get; set; }
      
        public PreviewBlock(PageData currentPage,IContent previewContent) 
            : base(currentPage)
        {
            this.PreviewContent = previewContent;
            this.ContentArea = new ContentArea();
            this.ContentArea.Items.Add(new ContentAreaItem
            {
                ContentLink = this.PreviewContent.ContentLink
            });

        }
    }
}

Block edit page view model

Example: View model for the block. Note: The IPageViewModel is a pattern from the Alloy sample site and it not required if the site not based on Alloy.

namespace MyEpiserverSite.Models.ViewModels
{
    public class BlockEditPageViewModel : IPageViewModel<SitePageData>
    {
        public BlockEditPageViewModel(PageData page, IContent content)
        {
            previewBlock = new PreviewBlock(page, content);
            CurrentPage = page as SitePageData;
        }

        public PreviewBlock previewBlock { get; set; }
        public SitePageData CurrentPage { get; set; }
    }
}

Preview controller

PreviewController inherits from the ActionControllerBase and implements IRenderTemplate<BlockData>, making the controller able to render block types. The Index method is overridden and gets the start page as rendering context. A new instance of the PreviewBlock page type is created, and the block is programmatically added to the content area. The controller has a TemplateDescriptor "Preview" tag, ensuring that it is only used for on-page editing.

Example: The preview controller. If the site is using dependency injection this example should be changed to take the IContentLoader dependency as constructor injection instead.

namespace MyEpiserverSite.Controllers
{
    [TemplateDescriptor(Inherited=true,
        TemplateTypeCategory = TemplateTypeCategories.MvcController, 
        Tags = new[]{RenderingTags.Preview, RenderingTags.Edit},
        AvailableWithoutTag =false)]

    public class PreviewController : ActionControllerBase, IRenderTemplate<BlockData>
   
    {
        public ActionResult Index(IContent currentContent)
        {
            var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
            var startPage = contentLoader.Get<PageData>(ContentReference.StartPage);
            var model = new BlockEditPageViewModel(startPage, currentContent);

            return View(model);
        }
    }
}

Preview view

Example: View for rendering the block in different widths depending on context.

@model MyEpiserverSite.Models.ViewModels.BlockEditPageViewModel

<div class="row">
    <div class="span12">
        @Html.PropertyFor(m => m.previewBlock.ContentArea)
    </div>
</div>

<div class="row">
    <div class="span8">
        @Html.PropertyFor(m => m.previewBlock.ContentArea)
    </div>
</div>

<div class="row">
    <div class="span4">
        @Html.PropertyFor(m => m.previewBlock.ContentArea)
    </div>
</div>

The resulting outcome when editing and previewing a block in edit view.

Related topics

Comments

namespace MyEpiserverSite.Models.Pages
{
    public class PreviewBlock : PageData
    {
        public IContent PreviewContent { get; set; }
        public ContentArea ContentArea { get; set; }
      
        public PreviewBlock(PageData currentPage,IContent previewContent) 
            : base(currentPage)
        {
            this.PreviewContent = previewContent;
            this.ContentArea = new ContentArea();
            this.ContentArea.Items.Add(new ContentAreaItem
            {
                ContentLink = this.PreviewContent.ContentLink
            });

        }
    }
}

will the property not be virtual? it is giving error if its not virtual. but after putting it as virtual, it is asking for custom property defination using propertytypedefination?Please help

The "PreviewBlock" should not be registered as a content type (notice there is no ContentType attribute), hence no requirements on virtual properties.