Ayo Adesina
Ayo Adesina

Reputation: 2425

How to get block Items from a ContentArea based on its type

I have a page type with a ContentArea as one of its properties

(currentPage.PrimaryComponentArea)

How can I get the block items stored in this property based on its type.

I also want to be to access properties on the block so I need to convert it from ContentAreaItem to the actuall block type.

        public ActionResult Index(RatePlanPageType currentPage)
        {
          ..........

          var allItems = currentPage.PrimaryComponentArea.Items;

          var blocks = allItems.Where(x => bla bla bla  < Can I do it using linq

        }

this is my first Episerver project so I hope this is not a stupid question.

Upvotes: 1

Views: 5549

Answers (3)

Eric Herlitz
Eric Herlitz

Reputation: 26307

To solve this using linq

// ServiceLocator as example, use dependency injection!
var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();

// Get all CodeBlock's from the contentarea
IEnumerable<CodeBlock> items = currentPage.ContentArea?.Items?
    .Where(block => block.GetContent() is CodeBlock) // validate type
    .Select(block => contentLoader.Get<CodeBlock>(block.ContentLink));

// Run a where on a specific property on the blocks
IEnumerable<CodeBlock> items = currentPage.ContentArea?.Items?
    .Where(block => block.GetContent() is CodeBlock) // validate type
    .Select(block => contentLoader.Get<CodeBlock>(block.ContentLink))
    .Where(block => block.Tags.Contains("Episerver"));

Now the trick here is to use the .Where(block => block.GetContent() is CodeBlock), the block.GetContent() will resolve an IContent object which allows you to verify the type of the block

For a more generic approach use this

IEnumerable<IContent> items = currentPage.ContentArea?.Items?
    .Select(content => contentLoader.Get<IContent>(content.ContentLink))  // Get as IContent
    .Where(content => content.Name.Contains("block")); // any properties you like

The last version will also include pages if they are dropped in the contentarea, if you only like to support a specific type use the same type validation

IEnumerable<IContent> items = currentPage.ContentArea?.Items?
    .Where(content => content.GetContent() is BlockData) // validate type
    .Select(content => contentLoader.Get<IContent>(content.ContentLink))
    .Where(content => content.Name.Contains("block"));

Always check variables if they are null when using null propagation as I do ContentArea?.Items?...

if(items != null) {
    // Yay!
}

Upvotes: 1

Gosso
Gosso

Reputation: 141

var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
if (page != null && page.ContentArea != null && page.PrimaryComponentArea.Items.Any())
{
    foreach (var contentItem in page.PrimaryComponentArea.Items)
    {
        var item = contentLoader.Get<YOUR_CONTENT_TYPE>(contentItem.ContentLink);
        // do your stuff
    }
}

Items in ContentArea are saved as ContentReference, and all ContentReference reference to an IContent. A block and page type is an IContent.

If you want to restrict contentareas to one type: [AllowedTypes(new [] {typeof(PageData), typeof(BlockData)})]

https://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/9/Content/Properties/Property-types/Restricting-content-types-in-properties/

Upvotes: 5

Frostrar
Frostrar

Reputation: 337

        var resultList = new List<IContent>();
        var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();

        foreach (ContentAreaItem contentAreaItem in currentPage.PrimaryComponentArea.FilteredItems)
        {
            if (contentAreaItem != null && contentAreaItem.ContentLink != null &&
                contentAreaItem.ContentLink != ContentReference.EmptyReference)
            {

            IContent content;
            if (contentLoader.TryGet(contentAreaItem.ContentLink, out content))
                if (content != null)
                {
                    resultList.Add(content);
                }
            }
        }

Above code will give you a list of blocks in the contentarea as IContent. Note that I used FilteredItems which also takes into consideration any personlization, publish status etc.

To access the properties of the blocks you will need to cast them to their type. So something like this might point you in the right direction

  foreach (IContent content in resultList)
    {
                var block = content as YourBlockType;
                if (content != null)
                {
                    // the content is of type YourBlockType. Do work 
                }
    }

Upvotes: 1

Related Questions