Try our conversational search powered by Generative AI!

Linus Ekström
Dec 4, 2013
  16134
(3 votes)

Custom root for category selection and EditorDescriptorBehavior

In this blog post I’ll describe how to set a custom root for a category property. The code for this is pretty simple:

[EditorDescriptorRegistration(TargetType = typeof(CategoryList), UIHint = "customcategoryroot", EditorDescriptorBehavior = EditorDescriptorBehavior.ExtendBase)]
public class CategoryListEditorDescriptor : EditorDescriptor
{
    public override void ModifyMetadata(EPiServer.Shell.ObjectEditing.ExtendedMetadata metadata, System.Collections.Generic.IEnumerable attributes)
    {
        metadata.EditorConfiguration["root"] = Category.GetRoot().Categories[0].ID;
    }
}

The actual logic is pretty simple, set the “root” property to the widget that is responsible for editing (this only works in 7.5 due to some changes in the client widget to support this). In this sample the settings will only affect any CategoryLists tagged with the UIHint “customcategoryroot” but removing this will make the descriptor affect all category-properties, including the built in one.

EditorDescriptorBehavior

So how does the editing system know how to edit the property since we are not defining an editor widget? The answer to this is that we have defined the new attribute property EditorDescriptorBehavior. In this case we are setting this property to EditorDescriptorBehavior.ExtendBase which means that we want to run the default editor descriptors for the type (in this case the default descriptor for CategoryList without any UIHint) first and then this editor descriptor. This makes is possible to extend the behavior without taking having to know about the class responsible for the default implementation. There are a few posibilities to set for this property which the SDK explains like this:

/// 
/// Adds this descriptor to the list of descriptors for the given type and ui hint combination.
/// 
Default = 0,
/// 
/// Adds this descriptor to the list of descriptors for the given type and ui hint combination and
/// makes sure that the descriptors registered without a ui hint for the type are called before this descriptor.
/// 
/// This is only valid in combination with a ui hint.
ExtendBase = 1,
/// 
/// Removes any existing descriptors for the type/ui hint combination and then adds this descriptor.
/// 
OverrideDefault = 2,
/// 
/// Adds this descriptor last in the list of descriptors for the given type and ui hint combination.
/// 
/// If several descriptors are defined this way the order of execution is undefined.PlaceLast = 3

There is one known limitation that you might to be aware of: You cannot extend an editor descriptor that already has a UIHint defined. So if you want to extend ContentReferences hinted with for example a “Page”, you cannot override this behavior direcly (though this can be simply archieved which will be content for another blog post).

Dec 04, 2013

Comments

Chris Magee
Chris Magee Jul 31, 2014 12:13 AM

This doesn't seem to work in 7.5.

Visually, this works great. When you select categories and save, on refresh the categories are no longer selected.

Do you know why this might happen?

Aug 1, 2014 05:43 PM

@Christopher: I just tried on a site using the latest packages and it seems to work fine with me. In my testing I added a few categories under a specific node that I set as the root node for a specific property and I tried selecting categories both on the first level but also further down the hierarchy and they are still selected after I save and switch content and then go back to the item. Could you try getting the latest packages to see if that does any differences. If this does not solve your issues, could you write your repro steps more in detail?

Neil F
Neil F Nov 14, 2014 01:55 PM

This is really useful, thanks. I'm interested to understand how you knew the name of EditorConfiguration Dictionary key to set, do you know of other existing keys? Specifically we have a requirement to sort the categories and was hoping it would be as straightforward as using a similar setting.

Nov 14, 2014 03:24 PM

Hi!

Actually, the reason for this specific property and my knowledge of this is that we heard the request to be able to changes this a few times. So we moved out the root for the responsible editor to a setting that can be overridden on the server side. From what I can see, this setting is the only settings that can currently be altered.

Neil F
Neil F Nov 17, 2014 01:23 PM

Hi Linus - thanks for that, will try and dissuade the customer for now!

Jan 14, 2015 10:17 PM

Hi Linus,



i tried this method to write over the PageCategory (episerver default property) without any success.

Do you have any suggestions how i can set new root on the episerver default categorylist property Category (PageCategory)

Jan 15, 2015 01:54 PM

Hi Radek!

I noticed you had to do a few changes to make it work for the default categories. First of all, I moved the logic for setting the editor setting from the constructor to a method. This is mostly for performance reasons since the base class would otherwise do some things that we don't need. The trick to make it work (except the obvious thing to remove the UIHint), is to change EditorDescriptorBehavior to EditorDescriptorBehavior.PlaceLast. The reason for this is that we have removed the UI hint and therefore want to have two editor descriptors for the same type/uihint combination. I hope this solves your issue.

Jan 29, 2015 04:05 PM

This code sample works for me:

using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.Shell.ObjectEditing.EditorDescriptors;

namespace UIExtensionSamples.EditorDescriptors
{
[EditorDescriptorRegistration(TargetType = typeof(CategoryList), EditorDescriptorBehavior = EditorDescriptorBehavior.PlaceLast)]
public class CustomCategoryRootEditorDescriptor : EditorDescriptor
{
public CustomCategoryRootEditorDescriptor()
{
//We set the root property to the editor to alter the root category for the category picker dialog.
//EditorConfiguration["root"] = Category.GetRoot().Categories[0].ID;
}

public override void ModifyMetadata(EPiServer.Shell.ObjectEditing.ExtendedMetadata metadata, System.Collections.Generic.IEnumerable attributes)
{
metadata.EditorConfiguration["root"] = Category.GetRoot().Categories[0].ID;
}

public const string CustomCategoryRoot = "customcategoryroot";
}
}

Jan 30, 2015 08:07 AM

Hi Linus,

sorry for my prev post. I noticed it works great.
I have another question that you might help me out with?
If i would like to change the name of episervers property with name "Category" to "Related products"
JUST when a particular block is loaded.
So, all over the place it should the name Category be used but when user loads a special block it should state "Related Products"

[EditorDescriptorRegistration(TargetType = typeof(CategoryList), EditorDescriptorBehavior = EditorDescriptorBehavior.PlaceLast)]
public class CategoryListEditorDescriptor : EPiServer.Shell.ObjectEditing.EditorDescriptors.EditorDescriptor
{
public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable attributes)
{

dynamic contentMetadata = metadata;
var ownerContent = contentMetadata.OwnerContent as IContent;
var ownerType = ownerContent.GetType().BaseType;

if (ownerType != null && ownerType.Name == "SpecialBlock")
{
var categoryService = ServiceLocator.Current.GetInstance();
var category = categoryService.GetCategoryStartNode(Categories.Industry);
if (category != null)
EditorConfiguration["root"] = category.ID;

base.ModifyMetadata(metadata, attributes);
if (metadata.PropertyName == "icategorizable_category")
{
metadata.DisplayName = "Related products";
metadata.ShortDisplayName = "Related products";
metadata.SimpleDisplayText = "Related products";
}
}

}

}

I have tried altering the EditorDescriptorBehavior.PlaceLast to different options without any success.

Maybe doing something wrong?

Feb 2, 2015 09:47 PM

Also tried setting a new name on init (IInitializableModule)

Manage to do it on all properties that are not episerver default.
This means that episerver changes the name somewhere down the road back to "Category".

Feb 3, 2015 03:56 PM

Display names for properties are handled by localization in EPiServer. It seems that this is done after the metadata is created and that's the reason why changing the metadata has no effect. I would simply add a new Catagory property for your custom type and hide the built in category property for your property( by setting metadata.ShowForEdit = false;).

Yagnik Jadav
Yagnik Jadav Mar 26, 2019 12:27 PM

Hey,

I am trying to add custom root node in Select Image dialog decorated with UIHint.Image.

I am using custom media content peovider and EntryPoint is set under root and not inside asset folder.

So  I would like to extend existing ImageReference Editor descriptor for type IContentImage and UIHint.Image to include custom root in left side of dialog.

Your help will be appreciated.

Regards Yagnik

Linus Ekström
Linus Ekström Mar 26, 2019 12:59 PM

Hi Yagnik,

This technique can be used whenever you have an editor that uses different properties. Basically, properties set will override default property values and I've recently used it for another scenario that I plan to blog about.

In your case, you need to have a look at the editor widget that you want to change and see if it has a property to override, and in that case you can apply it either to all properties of a given type, or properties with a given UIHint for editors.

Regards
Linus

Please login to comment.
Latest blogs
Optimizely Web... 6 Game Changing Features in 2024

If you are interested in learning about what's new within Optimizely Web, you are in the right place. Carry on reading to learn about the 6 greates...

Jon Jones | Mar 3, 2024 | Syndicated blog

Headless forms reloaded (beta)

Forms is used on the vast majority of CMS installations. But using Forms in a headless setup is a bit of pain since the rendering pipeline is based...

MartinOttosen | Mar 1, 2024

Uploading blobs to Optimizely DXP via PowerShell

We had a client moving from an On-Prem v11 Optimizely instance to DXP v12 and we had a lot of blobs (over 40 GB) needing uploading to DXP as a part...

Nick Hamlin | Mar 1, 2024 | Syndicated blog

DbLocalizationProvider v8.0 Released

I’m pleased to announce that Localization Provider v8.0 is finally out.

valdis | Feb 28, 2024 | Syndicated blog

Epinova DXP deployment extension – With Octopus deploy

Example how you can use Epinova DXP deployment extension in Octopus deployment.

Ove Lartelius | Feb 28, 2024 | Syndicated blog

Identify Azure web app instance id's for an Optimizely CMS site

When running Optimizely CMS in Azure, you will be using an instance bound cloud license. What instances are counted, and how can you check them? Le...

Tomas Hensrud Gulla | Feb 27, 2024 | Syndicated blog