The problem is that EPiServer thinks that you want to render a link to that content. And since a block doesn't have a url it will just output the link title. You need to tell EPiServer that you actually want to render the content of the target block.
I would first extend my viewmodel with the actual block (in my case the EditorialBlock)
public class StartPageContentModel : PageViewModel<StartPage> { public StartPageContentModel(StartPage currentPage) : base(currentPage) { } public EditorialBlock EditorialBlock { get; set; } }
In the StartPage contenttype you can have like you have with a content reference (although you might want to consider if a local block will do instead?)
[AllowedTypes(typeof(EditorialBlock))] public virtual ContentReference EditorialBlockLink { get; set; }
In the page controller I can then use the content loader to load the actual block from the reference
public class StartPageController : PageControllerBase<StartPage> { private readonly IContentLoader _contentLoader; public StartPageController(IContentLoader contentLoader) { _contentLoader = contentLoader; }
---------------------
var model = new StartPageContentModel(currentPage); if (currentPage.EditorialBlockLink != null) { model.EditorialBlock = _contentLoader.Get<EditorialBlock>(currentPage.EditorialBlockLink); }
and then in my start page view I can render the block
@using EPiServerSiteV9 @model StartPageContentModel @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row equal-height", tag = Global.ContentAreaTags.FullWidth }) @if (Model.EditorialBlock != null) { @Html.PropertyFor(x => x.EditorialBlock) }
and the Editorial block view is
@model EditorialBlock <div class="clearfix" @Html.EditAttributes(x => x.MainBody)> @Html.DisplayFor(x => Model.MainBody) </div>
Another option is to create a UIHINT on the property for the ContentReference and a custom display template to render the property for the link and in the display template get the block. But I prefer to keep that logic in controller if possible. In my mind, display templates should grab data from a data source, it should format it.
Great answer! Thank you. These blocks will be reused on several pages so I think a global block is appropriate here. In this case, I don't have a controller or a view model that is specific to my page, so I think I'll try creating an HtmlHelper extension to retrieve the Block content given the ContentReference like you've shown in your controller.
I fundamentally agree with you on the concept of the controller providing the content to the view rather than a view going and retrieving the content, but I think the display template approach is, more or less, how EPiServer goes about rendering the blocks when they are placed in a ContentArea already. So maybe it's not a terrible idea in terms of consistency, but if there's already a controller, I'd go with your initial suggestion.
Thanks again. I didn't know if I was missing something.
There is another way to achieve this, which I usually prefer. Create a display template for "partial" content...
First use a tag when rendering the property:
@Html.PropertyFor(m => m.WorldwideMapBlock, new { Tag = "ContentReferencePartial" })
Then create a template in /shared/DisplayTemplates/ and name i ContentReferencePartial.cshtml (same name as the tag).
Put this in the template:
@using EPiServer.Core @model ContentReference @if (!ContentReference.IsNullOrEmpty(Model)) { Html.RenderContent(Model); }
Then you need this HtmlHelper:
public static void RenderContent(this HtmlHelper html, ContentReference contentLink) { var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>(); IContentData contentData; if (contentLoader.TryGet(contentLink, out contentData)) { html.RenderContentData(contentData, false); } }
Oh and of cource you need a view for the block which you've selected in your property WorldWideMapBlock. You probably already have a view for this block.
This approach work for both MediaData, PageData and BlockData which is nice. Local block/block as property isn't always what we need in the model, sometimes we need to give the editor the possibilty to change between two different blocks.
I am trying to create a page that allows an editor, through on page editing, to drag and drop one, and only one, block onto the page. So in my page type, I have created a property of the block type. In on page editing, I am able to drag and drop the block like I want, but when I go view the page, all that shows is the name of the block instead of the actual block content.
Page Type
Page View
Block View
How do I render the block's view from a ContentReference property?