Calling all developers! We invite you to provide your input on Feature Experimentation by completing this brief survey.
Calling all developers! We invite you to provide your input on Feature Experimentation by completing this brief survey.
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?