Error when using List of ContentArea

Vote:
 

I don't see anything in the training materials or documentation for what I'm trying to do.

I would like to create a page with a list of ContentAreas that the user can specify how many areas they want and blocks inside each.  I'd also like to include restrictions on how many areas and blocks are allowed.  Here is the code example:

[SiteContentType(DisplayName = "Fun Page",
    GroupName = Global.GroupNames.Default]
public class ExamplePage : BasePage
{
    [Display(Name = "First Position Block",
       GroupName = Global.GroupNames.Default,
       Order = 60)]
    [AllowedTypes(typeof(BaseBlock))]
    [ItemRange(1, 10)]
    [ListItems(2)]
    public virtual List<ContentArea> BlockSections { get; set; }
}

I'm getting an error stating my property is not an allowed type on the class:  

The property 'BlockSections' on the content type 'ExamplePage' has a type that does not support the AllowedTypesAttribute.AllowedTypes is only supported on properties of types: 'ContentReference', 'ContentArea', 'IEnumerable`1'.

When I remove the [AllowedTypes] attribute I get a different error:

EPiServer.Core.TypeMismatchException: Type 'System.Collections.Generic.List`1[[EPiServer.Core.ContentArea, EPiServer, Version=11.14.2.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7]]' could not be mapped to a PropertyDefinitionType

Is what I'm trying to do possible or is there a better way? The only way I can get this to work is if I create multiple ContentArea properties which is not maintainable.

Thanks.

#223496
May 28, 2020 17:43
Vote:
 

Why do you need more than one ContentArea? You can put as many blocks you would like inside just one.



Episerver has no concept of a property of type List<ContentArea>

Episerver let you use a list of primitive values as a property, see:
https://world.episerver.com/documentation/developer-guides/CMS/Content/Properties/property-value-list/

And a list of custom objects:
https://world.episerver.com/documentation/developer-guides/CMS/Content/Properties/generic-propertylist/

I am not sure if this will work, but I think you will have to start by telling Episerver that List<ContentArea> should be used as a property type:

[PropertyDefinitionTypePlugIn]


Another suggestion, a ContentArea with blocks, where each block contains a content area:

[SiteContentType(DisplayName = "Fun Page",
    GroupName = Global.GroupNames.Default]
public class ExamplePage : BasePage
{
    [Display(Name = "First Position Block",
       GroupName = Global.GroupNames.Default,
       Order = 60)]
    [AllowedTypes(typeof(FunBlock))]
    public virtual ContentArea BlockSections { get; set; }
}



[SiteContentType(DisplayName = "Fun Block",
    GroupName = Global.GroupNames.Default]
public class FunBlock: BaseBlock
{
    [AllowedTypes(typeof(BaseBlock))]
    public virtual ContentArea Blocks { get; set; }
}


And, if you are using blocks inside blocks, maybe this can come in handy:

https://world.episerver.com/blogs/grzegorz-wiechec/dates/2019/7/episerver-labs---block-enhancements/

#223519
Edited, May 29, 2020 6:59
Vote:
 

Hi RichF,

Episerver doesn't support List<ContentArea> so you can't use it but you can use single ContentArea to inset multiple blocks.

For Maximum allowed item you can refer this-

https://world.episerver.com/blogs/paul-gruffydd/dates/2018/10/limiting-the-number-of-items-in-a-content-area-while-supporting-personalisation/

https://world.episerver.com/blogs/tuan-do/dates/2017/8/limiting-items-in-a-contentarea/

#223553
May 29, 2020 14:07
Vote:
 

Ok I think using a single ContentArea will work with my design.  Thank you for your responses.

I wanted to be able to insert markup around each ContentArea when rendering the view.  I have a similar need to render the different block types within the ContentArea with some wrapping markup.

Adding to the example code above, let's say that BaseBlock has implementations (from the AllowedTypes attribute) with custom views.  How can I enumerate the blocks from the ContentArea and call the appropriate block view?

@model FunBlock

<div class="row">
@{ 
    foreach(var block in Model.Blocks.Items)
    {
        <div class="col">
            @Html.DisplayFor(x => block) <-- This doesn't render correctly
        </div>
    }
}
</div>
#223557
May 29, 2020 17:13
Vote:
 

Try this-

@foreach (var item in Model.MainContent.FilteredItems.Select(x => x.GetContent()))
{
    if (item is CalloutBlock calloutBlock)
    {
        @Html.PropertyFor(x => calloutBlock.Title)
    }
    else if (item is ParagraphBlock paragraphBlock)
    {
        @Html.PropertyFor(x => paragraphBlock.CopyTop)
    }
}
#223558
May 29, 2020 17:44
Vote:
 

I was able to get this working based on your example.  I had to import the EpiServer.Core using to get the extension containing GetContent() method available on ContentAreaItem.

I would prefer to avoid having to manage conditions and casting types if possible.  I saw others use @Html.RenderContentData() which seemed like an option for that but has different requirements that I couldn't get working.  See:  iterating-through-unique-contentarea-items

EDIT:  I was able to get this working without conditions and casting by:

@{ 
    foreach (var block in Model.Blocks.FilteredItems.Select(x => x.GetContent()))
    {
        <div class="col">
            @{ Html.RenderContentData(block, true); }
        </div>
    }
}

Thank you all!

#223559
Edited, May 29, 2020 19:01
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.