在块 ajax 调用中获取 currentBlock 的最佳方法是什么?
[HttpGet]
public ActionResult GetSomething()
{
var currentBlock = Get(); //how?
return currentBlock.SomeLabel;
}
(当 Block 或 BlockController 不知道 Page 时,我不知道解决方案)
我想让块可用于任何页面。
谢谢。
在块 ajax 调用中获取 currentBlock 的最佳方法是什么?
[HttpGet]
public ActionResult GetSomething()
{
var currentBlock = Get(); //how?
return currentBlock.SomeLabel;
}
(当 Block 或 BlockController 不知道 Page 时,我不知道解决方案)
我想让块可用于任何页面。
谢谢。
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}.");
}
}
为什么不添加路线呢?所以无论在哪里使用块,URL 都是一样的?或者将操作放在所有页面控制器的基类中。然后,您必须从块的视图中传递对操作的引用。