EPiServer : Creating A Custom Checkbox Category PageType Picker Control

EPiserver is great at a lot of things but I think it’s tagging does let it down a bit without having to buy one of the bulk upgrade products.   In EPiserver all you can do is define a single global category that is available to all page templates.  We had a requirement to create different categories based on different page types.  If we added a global category then editors would be able to add in wrong categories for their page type.

I found a good article here that solved a similar problem, however when I implemented it I had a lot of issues around saving.  With the proposed solution, if you clicked save twice the data would be lost.  I made an update to only publish but this made other fields break.   In my site I have created a new category section as shown :

Screenshot_5

When I define my property (I’ll get to that later) I use the ‘HelpText’ attribute to define which part of the category tree the property should use, as seen below the HelpText matches the name I’ve set-up in my categories.

        [PageTypeProperty(EditCaption = "Tags", 
Type = typeof(PropertyCategoryCheckBoxList), 
HelpText = "ArticleRoot", 
SortOrder = 100,
Tab = typeof(ArticlesTab))]
public virtual string TagIds { get; set; }

One important thing to note about this process is that even though the type is of  ‘PropertyCategoryCheckboxList’ the property is string.  What this means is when we iterate through the control list later any selected ID will have to be stored in a comma separated string.

First define the property class :

[PageDefinitionTypePlugIn(DisplayName = "Category Checkbox List")]
public class PropertyCategoryCheckBoxList : PropertyMultipleValue
{
public override IPropertyControl CreatePropertyControl()
{
return new PropertyCategoryCheckBoxListControl();
}
}

Next we need to define the control class:

 public class PropertyCategoryCheckBoxListControl : PropertySelectMultipleControlBase
{
private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger
(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private List CategorgyIds;
protected override void SetupEditControls()
{
Category parentCategory = null;
var definition = PageDefinition.Load(PropertyData.PageDefinitionID);
if (!string.IsNullOrEmpty(definition.HelpText))
{
parentCategory = Category.Find(definition.HelpText);
}
if (parentCategory == null)
{
parentCategory = Category.Find(Name);
}
if (parentCategory == null)
{
parentCategory = Category.GetRoot();
}
CategorgyIds = GetCategoryIds(PropertyData.Value.ToString());
foreach (Category  category in parentCategory.Categories)
{
var li = new ListItem(category.Description, category.ID.ToString(CultureInfo.InvariantCulture));
li.Selected = CategorgyIds.Any(c => c == category.ID);
EditControl.Items.Add(li);
}
}
private List GetCategoryIds(string categories)
{
if (string.IsNullOrEmpty(categories)) return null;
var categoryIdList = new List(); 
try
{
categoryIdList.AddRange(categories.Split(',').Select(id => Convert.ToInt32(id)));
}
catch (Exception ex)
{
Logger.Error(ex);
}
return categoryIdList;
}
}

In the code above we’re :

  • Getting the value of help text and then querying the category list to get all the children
  • Getting any existing user selection (stored in ProperyData.Value as a comma seperated string) and then calling GetCategoryIds
  • GetCategoryIds passes that string into a list of Id’s
  • Add the controls to the page and select any of the entries that have been previously selected.

The last part of the puzzle is ApplyEditChange and storing the selected values, which was the main issue I had with the code I found on-line.

        public override void ApplyEditChanges()
{
base.ApplyEditChanges();
try
{
var categoryIdList = new List();
foreach (ListItem li in EditControl.Items)
{
if (li.Selected)
{
var categoryId = Category.Find(Convert.ToInt32(li.Value)).ID;
categoryIdList.Add(categoryId.ToString());
}
}
PropertyData.Value = String.Join(",", categoryIdList);  
}
catch (Exception ex)
{
Logger.Error(ex);
}
}

The big difference with my code that I’m storing is the users selection is stored using the PropertyData.Value rather than creating a clone and saving that clone and creating all the nastiness that causes.  All the code is doing :

  • Loop through the checkboxlist displayed and store anything that is ticked in categoryIdList
  • Iterate through cateogryIdList and create a string of Id’s seperated by a comma
  • Store this string using PropertyData.Value

If the code above works in you should have a check box list on your page type that pulls in all the child categories.

Screenshot_6

 

 

PropertyCategoryCheckBoxListControl

 

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *