Extend your functionality by using Blocks

I’ve found that you can create a small toolbox for the editor to change the behavior of your functionality by using Blocks, not as models but as pluggable functions. It’s quite similar to visual programming where you play around with boxes and arrows but in this case we create Blocks and drag them either to a ContentReference or a ContentArea.

Functionality Blocks

The idea came from a project where multiple web sites are using their own instance of the same EPiServer project. Each website had different requirements of filters and I needed something generic where a super user could setup and change the functionality.

Cut to the code

First I created an interface that I will put on each BlockType:

    public interface IDoSomethingWithPageLists : IContentData
    {
        IEnumerable<PageData> DoSomething(IEnumerable<PageData> pages);
    }

In my first implementation, say you’re listing lots of pages and the editor wants to reverse the order, this is a really silly example though.

    [ContentType(DisplayName = "Reverse pages", GUID = "1f58e116-6576-4737-8d2c-246010b5b302")]
    public class ReverseBlock : BlockData, IDoSomethingWithPageLists
    {
        [Display(
            Name = "Property Name",
            GroupName = SystemTabNames.Content,
            Order = 1)]
        public virtual string PropertyName { get; set; }

        public IEnumerable<PageData> DoSomething(IEnumerable<PageData> pages)
        {
            return pages.Reverse();
        }
    }

That was quite easy, you can also give the editor the possibility to give details or variables to the logic. Such as filtering on that a property requires a value.

    [ContentType(DisplayName = "Property must contain value", GUID = "25ed56de-0d0b-43bb-8beb-8a8442e1bdd1")]
    public class PropertyMustContainValueBlock : BlockData, IDoSomethingWithPageLists
    {
        [Display(
            Name = "Property Name",
            GroupName = SystemTabNames.Content,
            Order = 1)]
        public virtual string PropertyName { get; set; }

        public IEnumerable<PageData> DoSomething(IEnumerable<PageData> pages)
        {
            return pages.Where(p => p[this.PropertyName] != null);
        }
    }

And just for the case of repeating the possibility of letting the editor decide.

    [ContentType(DisplayName = "Take every #", GUID = "7b9f13a6-22fe-4c0f-a804-ff81879fa986")]
    public class TakeEveryBlock : BlockData, IDoSomethingWithPageLists
    {
        [Display(
            Name = "Take Every",
            GroupName = SystemTabNames.Content,
            Order = 1)]
        public virtual int TakeEvery { get; set; }

        public IEnumerable<PageData> DoSomething(IEnumerable<PageData> pages)
        {
            for (int i = 0; i < pages.Count(); i++)
            {
                if (i % this.TakeEvery == 0)
                {
                    yield return pages.ElementAt(i);
                }
            }
        }
    }

So in my Page Template, all I need to do iterate through my Blocks and let them do what they’re good at.

    IEnumerable<PageData> pages = GetChildren(CurrentPage.PageLink); // Getting children is only a simple example.

    if (CurrentPage.FunctionBlocks != null)
    {
        var blocks = this.CurrentPage.FunctionBlocks.FilteredItems.Select(x => this.Get(x.ContentLink)).Where(x => x != null);
        foreach (var block in blocks)
        {
            pages = block.DoSomething(pages);
        }
    }

    // Do something with the pages such as binding a Repeater/PageList or adding to a Model

Summary

This is a really simplified example how the editor easily plugg in some customized logic to my existing function.

It can sometimes be a little confusing for the editor if you use Functionality Blocks to create a too complex solution. But to simplify for the editor, you can use EditorDescriptors or creating custom Dojo components to help your Editor.

In this example, I’m automatically adding the filters. You can also render these blocks to the visitor and let the visitor activate the logic.

Leave a comment