I can see that in Foundation for .NET 5 they have usage through .Require
using EPiServer.Framework.Web.Resources;
using EPiServer.Web.Mvc;
using Foundation.Features.Shared;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Foundation.Features.Blocks.Healthbot
{
public class HealthChatBotBlockController : AsyncBlockComponent<HealthChatbotBlock>
{
private readonly IRequiredClientResourceList _requiredClientResourceList;
public HealthChatBotBlockController(IRequiredClientResourceList requiredClientResourceList)
{
_requiredClientResourceList = requiredClientResourceList;
}
protected override async Task<IViewComponentResult> InvokeComponentAsync(HealthChatbotBlock currentBlock)
{
_requiredClientResourceList.Require(HealthBotClientResourceProvider.BotJs).AtHeader();
var model = new BlockViewModel<HealthChatbotBlock>(currentBlock);
return await Task.FromResult(View("/Features/Blocks/HealthBot/HealthChatBotBlock.cshtml", model));
}
}
[ClientResourceProvider]
public class HealthBotClientResourceProvider : IClientResourceProvider
{
public static string BotJs = "healthbot.webchat";
public IEnumerable<ClientResource> GetClientResources()
{
return new[]
{
new ClientResource
{
Name = BotJs,
ResourceType = ClientResourceType.Html,
InlineContent = @"<script crossorigin=""anonymous"" src=""https://cdn.botframework.com/botframework-webchat/latest/webchat.js""></script>"
}
};
}
}
}
Thanks for helping, Scott!
No luck, though.
I tried with a separate IClientResourceProvider, but requiring the script in InvokeComponentAsync doesn't result in the script being loaded.
However, if I add IClientResourceRegistrator, the script gets loaded - but that defeats the purpose since it results in the script being loaded regardless of whether my block type is rendered on the page.
[ClientResourceProvider]
public class MyResourceProvider : IClientResourceProvider
{
public static string ResourceName = "someResource";
public IEnumerable<ClientResource> GetClientResources()
{
return new[]
{
new ClientResource
{
Name = ResourceName,
ResourceType = ClientResourceType.Script,
Dependencies = new List<string> { "someDependency" },
Path = "https://temp.uri/somescript.js"
}
};
}
}
[ClientResourceRegistrator]
public class ClientResourceRegister : IClientResourceRegistrator
{
public void RegisterResources(IRequiredClientResourceList requiredResources)
{
// Always results in the script being loaded (not just when a ContactFormBlock is rendered on the page)
requiredResources.Require(MyResourceProvider.ResourceName);
}
}
public class ContactFormBlockViewComponent : AsyncBlockComponent<ContactFormBlock>
{
private readonly IRequiredClientResourceList _requiredClientResourceList;
public ContactFormBlockViewComponent(IRequiredClientResourceList requiredClientResourceList)
{
_requiredClientResourceList = requiredClientResourceList;
}
async protected override Task<IViewComponentResult> InvokeComponentAsync(ContactFormBlock currentContent)
{
// Does not result in script being loaded
_requiredClientResourceList.RequireScript(MyResourceProvider.ResourceName);
return await Task.FromResult(
View("~/Features/ContactForm/ContactForm.cshtml", currentContent)
);
}
}
@Ted, as far as I know, I don't think you can register client resources from a Component.
You can do it from a controller:
_requiredClientResourceList.Require("fancy_script")
.AtHeader();
Failed to get this to work, and instead went with a rather hacky solution that hurts my eyes...
In a nutshell: the Razor page model determines if the page includes blocks that require specific client resources.
public class OnePagerModel : RazorPageModel<OnePager>
{
private readonly IRequiredClientResourceList _requiredClientResourceList;
public OnePagerModel(IRequiredClientResourceList requiredClientResourceList)
{
_requiredClientResourceList = requiredClientResourceList;
}
public void OnGet()
{
// Iterate over blocks in a content area to see if there are any blocks that require specific client resources
var contentAreaContents = CurrentContent.MyContentArea.FilteredItems.Select(x => x.GetContent());
if (contentAreaContents.Any(x => x is ContactFormBlock))
{
_requiredClientResourceList.Require("contactFormBlock").StylesOnly().AtHeader();
_requiredClientResourceList.Require("contactFormBlock").ScriptsOnly().AtFooter();
}
}
}
This is a known issue. Requiring resources from a partial view/compontent has stopped working in CMS12. The fix will be released in 12.4.0 https://world.optimizely.com/support/Bug-list/bug/CMS-21308.
I want specific client resources to be loaded only when a specific block type is rendered on a page, but I'm not sure how to do it in CMS 12.
I was under the impression that client resources can be required at any time, even within Razor views/pages using something like:
I've also tried adding it to the ViewComponent type like so:
However, the script isn't added, despite the code above being executed.
The layout file contains the following:
It does work if I require the script through a class implementing IClientResourceRegistrator, but then the script always gets rendered, instead of only when a block of a specific type is rendered on the page.