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.
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.