November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
Just a heads-up, there have been a lot of updates to the NET5 version of Foundation in the past week, including some Forms-related updates. Note that it's now using the "main" branch for the official CMS 12 version (no longer using the net5 branch).
Great saw that!
I can see Foundation now have the views in Features/Shared/Views/ElementBlocks.
Just a curious question, is there a reason (that would be good to know) why Foundation have copied the element/forms views there instead of using the episerver form routes to the views in the forms module? Since I cant see that you have changed anything in the views.
Couldnt you have looked in the Features shared folder first and then fallback to FormsViews? https://github.com/episerver/Foundation/blob/main/src/Foundation/Infrastructure/Display/FeatureViewLocationExpander.cs
"/Features/Shared/Views/ElementBlocks/{0}.cshtml",
"~/FormsViews/Views/ElementBlocks/{0}.cshtml",
We added custom classes to the forms so they are not the same. Also for consistency we put them in the Features/Shared
How does your CustomFormContainerBlockController look? I'm seeing some issues in migrating a custom form container from CMS 11 to CMS 12.
Previously it was inheriting from FormContainerBlockController. Should it inherit from BlockComponent<T> now?
Is there an updated version of this page from the developer docs?
docs.developers.optimizely.com/content-cloud/v1.2.0-forms/docs/creating-a-custom-form-block
Hehe ye that specific developer docs page is not updated for CMS12+ / Forms 5+
You should still inherit from FormContainerBlockController but even if they kept the name the did change the type. FormContainerBlockController now inherits from BlockComponent<FormContainerBlock>.
Here is what our InvokeComponents looks like:
protected override IViewComponentResult InvokeComponent(
FormContainerBlock currentBlock)
{
//override viewpath
var baseResult = base.InvokeComponent(currentBlock) as ViewViewComponentResult;
baseResult.ViewName = "~/Views/FormContainerBlock/FormContainerBlock.cshtml";
// ... other logic ... example adding stuff to ViewBag which can be used in the custom razor view
return baseResult;
}
We use a custom built forms container that looks like this:
[TemplateDescriptor(AvailableWithoutTag = true,
ModelType = typeof(CustomFormContainer),
TemplateTypeCategory = TemplateTypeCategories.MvcPartialComponent)]
public class CustomFormContainerController : FormContainerBlockController
{
protected override IViewComponentResult InvokeComponent(FormContainerBlock currentBlock)
{
// Custom code...
return base.InvokeComponent(currentBlock);
}
}
And I get the following error when I visit a page with our custom block:
InvalidOperationException: The view 'Components/CustomFormContainer/FormContainerBlock' was not found.
In the examples above it seems like this error is resolved by coping Optimizley's FormContainerBlock.cshtml from the zip file located under "/modules" to "Views/Shared/Components/CustomFormContainer/FormContainerBlock.cshtml".
Optimizly's documentation says the same thing: https://docs.developers.optimizely.com/content-cloud/v1.2.0-forms/docs/creating-a-custom-form-block (unfortunately not updated for CMS 12).
As far as I can see we didn't have to do that on our old project that runs CMS 11.
Is this the only way to render the view if you want a custom forms container?
What I don't like about that solution is that we have to keep the copied file updated when ever we update Optimizley Forms.
All suggestions are very welcome. :)
We were using a custom built forms container in CMS 11 and we did have to do what's described in the documentation; make required changes to the ascx file and copy to Views/Shared/ElementBlocks folder.
I'm assuming this is how it's done in CMS12 also, but with the razor file instead of the web forms file.
Now in CMS12, my controller looks like yours Lucas. It's now working when in edit mode, but I get a runtime error when viewing the page as an end-user.
RuntimeBinderException: Cannot convert null to 'bool' because it is a non-nullable value type
on line 165 in CustomFormsContainerBlock.cshtml var validationCssClass = ViewBag.ValidationFail ? "ValidationFail" : "ValidationSuccess";
I realized what I was missing when looking at this problem on a new day with a fresh mind.
Camilla used Html.PartialAsync to render Optimizley's forms container view.
So instead of coping Optimizley's view from the zip folder I ended up with a view that looks like this:
@model EPiServer.Forms.Implementation.Elements.FormContainerBlock
@await Html.PartialAsync("FormContainerBlock", Model)
Note that the view still has to be located here: "Views/Shared/Components/CustomFormContainer/FormContainerBlock.cshtml", and you need to use the "FormsViewLocationExpander" described above.
I'm happy with this solution since we don't have to keep our file in sync whenever Optimiley updates the nuget package.
Larry - So far I'm not experiencing the same problem your describing. Perhaps your custom forms container code does something to the ViewBag? You can also try to add a custom forms container to Alloy to ensure it's not something in your code that's causing the problem.
Hi
Just wanted to share something I found that might help someone else going forward or perhaps someone knows a better way of doing it.
Im running Optimizely CMS 12+ with Razor Pages and the new "/Features" structure from Foundation and was experiencing routing issues with the
FormcontainerBlock partial or specific Elementblocks after installing Optimizely Forms.
I could render the built in element types in the default FormContainer but when creating a custom FormContainer Block the application couldnt find the FormContainerBlock partial:
@await Html.PartialAsync("FormContainerBlock", Model) - Resulted in partial not found error
To fix this I had to add path:
~/FormsViews/Views/ElementBlocks/Components/{0}/{0}.cshtml
to my ViewExpander since the FormContainerBlock.cshtml partial is now in below"Views/ElementBlocks/Components/FormContainerBlock/"
in the Episerver.Forms moduleFoundation view expander example (running MVC): https://github.com/episerver/Foundation/blob/main/src/Foundation/Infrastructure/Display/FeatureViewLocationExpander.cs
Example:
Startup.cs
services.AddRazorPages(opt => opt.RootDirectory = "/Features")
.AddRazorOptions(ro => {
ro.ViewLocationExpanders.Add(new FormsViewLocationExpander());
});
FormsViewLocationExpander.cs
public class FormsViewLocationExpander : IViewLocationExpander
{
private readonly List<string> _viewLocationFormats = new List<string>()
{
"~/FormsViews/Views/ElementBlocks/{0}.cshtml",
"~/FormsViews/Views/ElementBlocks/Components/{0}/{0}.cshtml",
};
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context,
IEnumerable<string> viewLocations)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (viewLocations == null)
{
throw new ArgumentNullException(nameof(viewLocations));
}
var expandedLocations = viewLocations.Union(_viewLocationFormats);
foreach (var item in expandedLocations)
{
yield return item;
}
}
public void PopulateValues(ViewLocationExpanderContext context)
{
return;
}
}
Needed the view path for the FormContainerBlock.cshtml razor view for my custom formcontainer :D