What is the best way to get currentBlock in block ajax call?
[HttpGet]
public ActionResult GetSomething()
{
var currentBlock = Get(); //how?
return currentBlock.SomeLabel;
}
(I don't know the solution when Block or BlockController do not know about the Page)
I want to make blocks reusable for any page.
Thanks.
I think you'd have to pass in the content reference for the block, but that isn't so bad.
To start with, make sure your global.asax
class includes the standard mvc route in the override for the RegisterRoutes
method:
public class EPiServerApplication : EPiServer.Global
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
}
protected override void RegisterRoutes(RouteCollection routes)
{
base.RegisterRoutes(routes);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional });
}
}
I have a block that I've used for testing some things out; it has a Title property and Items - a list of content references.
[ContentType(DisplayName = "Super Happy Fun Block", GUID = "b5d5c00c-dc8e-4ada-8319-20fd3474d4e7", Description = "")]
public class SuperHappyFunBlock : BlockData
{
public virtual string Title { get; set; }
public virtual IList<ContentReference> Items { get; set; }
}
For this block, I'll create a view model that contains those properties plus a ContentReference property. You can probably do this inside your cshtml view file, but this keeps your view a little cleaner.
public class SuperHappyFunModel
{
public string Title { get; set; }
public IList<ContentReference> Items { get; set; }
public ContentReference ContentLink { get; set; }
}
Next, wire up the block's controller to use the view model. I'm also going to need some javascript files; those can be added here via the controller. See the Episerver documentation on Client Resources for more info on that.
public class SuperHappyFunBlockController : BlockController<SuperHappyFunBlock>
{
public override ActionResult Index(SuperHappyFunBlock currentBlock)
{
ClientResources.RequireScript("https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.12.0.min.js").AtFooter();
ClientResources.RequireScript("/static/js/SuperHappyFunBlock.js").AtFooter();
var model = new SuperHappyFunModel
{
Title = currentBlock.Title,
Items = currentBlock.Items,
ContentLink = (currentBlock as IContent)?.ContentLink ?? ContentReference.EmptyReference
};
return PartialView(model);
}
}
On the view, make sure the content reference gets rendered in a place where the javascript can find it. I'm going to use a data attribute called data-block-id
.
@model SuperHappyFunModel
<div class="SuperHappyFunBlockController" data-block-id="@Model.ContentLink.ToString()">
<p class="dynamic">Content goes here.</p>
</div>
The javascript file referenced in the block controller would need to look for all block instances on the page, and then for each one, make the ajax call. Keep in mind that if your block is used on a page as a property then it won't have a ContentLink
, since block properties do not inherit IContent
.
(function($) {
$('.SuperHappyFunBlockController')
.each(function (index, blockDiv) {
var $blockDiv = $(blockDiv),
blockId = $blockDiv.attr('data-block-id');
if (!blockId) {
console.log('This block must be a property on a page... no block id found!');
return;
}
$.ajax({
method: 'GET',
url: '/superhappyfunblock/getsomething/' + blockId,
success: function (data) {
console.log(data);
$blockDiv.find('.dynamic').text(data);
}
});
console.log(blockId);
});
})($);
Finally, the last thing to do would be to create the ajax method on the controller. This is going to expect a string parameter named "id" so that it conforms to the default MVC view we added back at the beginning. It's also going to use dependency injection on the controller to get an instance of IContentLoader
.
public class SuperHappyFunBlockController : BlockController<SuperHappyFunBlock>
{
public override ActionResult Index(SuperHappyFunBlock currentBlock)
{
// code omitted here for brevity...
}
private readonly IContentLoader _contentLoader;
public SuperHappyFunBlockController(IContentLoader contentLoader)
{
_contentLoader = contentLoader;
}
public ActionResult GetSomething(string id)
{
ContentReference blockReference;
if (!ContentReference.TryParse(id, out blockReference))
return HttpNotFound();
SuperHappyFunBlock block;
if (!_contentLoader.TryGet(blockReference, out block))
return HttpNotFound();
return Content($"This is some really cool stuff for the block named {((IContent) block).Name}.");
}
}