Custom selection factory populated with values from category repository

Vote:
 

We've created a custom selection factory for retrieving parent categories (i.e. categories with children, regardless of what their own parent category are) from the category repository. The list is rendered - ok (first image) The value is set - ok (second image - we can also tell the value is set from debugging and because the values are rendered in the view). But, when the block that has this selection factory is published, the selected value in the dropdown list appears empty (third image), although the value is set. Anyone experienced something similar and know to solve it?

The selection factory:

    public class MainCategorySelectionFactory : ISelectionFactory
    {
        private Injected<CategoryRepository> CategoryRepository;

        public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
        {
            var categories = CategoryRepository.Service.GetRoot().Categories;
            var str = string.Empty;
            var list = new List<Category>();
            var strings = new List<string>();

            var selectableCategories = GetCategoriesWithChildren(categories,str, strings, list)
                .Select((x, i) => new SelectItem
                {
                    Text = strings[i],
                    Value = x.ID
                });
            return selectableCategories;

        }

        private string GetCategoryDescriptionAndAncestors(Category cat, string str)
        {
            return cat.Parent.Name != Category.RootName
                ? str + " - " + cat.Description
                : cat.Description;
        }

        private List<Category> GetCategoriesWithChildren(CategoryCollection categories, string str, List<string> strings, List<Category> list)
        {
            foreach (var cat in categories.Where(x => x.Categories.Any()))
            {
                // Add current category and its ancestor path to lists
                list.Add(cat);
                strings.Add(GetCategoryDescriptionAndAncestors(cat, str));

                GetCategoriesWithChildren(
                    cat.Categories, 
                    GetCategoryDescriptionAndAncestors(cat, str), 
                    strings, 
                    list);
            }

            return list;
        }
    }

The model:

        [Display(
            GroupName = GroupNames.Content,
            Order = 10)]
        [SelectOne(SelectionFactoryType = typeof(MainCategorySelectionFactory))]
        public virtual string MainCategory { get; set; }

What am I missing?

#204125
May 20, 2019 13:06
Vote:
 

Hi,

I suspect the issue is that the values of your select items are integers but they're being stored as strings. If you change the code like this, it should work:

var selectableCategories = GetCategoriesWithChildren(categories,str, strings, list)
                .Select((x, i) => new SelectItem
                {
                    Text = strings[i],
                    Value = x.ID.ToString()
                });

Alternatively you could make your property type an integer but, unless you plan on renaming it, you may run into problems changing the property type from string to int.

#204138
May 20, 2019 15:47
Vote:
 

Possibly you've not set the backing type on your property? 

[BackingType(typeof(TYPE))]

You usually have to set this to know what the data type is that's being saved. It may not be saving the data and being lost so therefore not repopulating, I think I've had that before.

For example on an Enum property we use [BackingType(typeof(PropertyNumber))]

#204142
May 20, 2019 16:03
Vote:
 

It seems like you are storing the INT value in the string property. Could you please cast this to string and then have a try.

{
   Text = strings[i],
   Value = x.ID.ToString()
});
#204153
May 21, 2019 6:47
Vote:
 

I know people are suggesting ToString() ing that ID but that Value type is an Object type not a string. I checked this in some of our examples, for one of our working Enum selection factories we setting value to an Enum type (Originally based off http://joelabrahamsson.com/enum-properties-with-episerver/) and this works fine for us

#204161
May 21, 2019 9:45
Vote:
 

Although it's possible the default backing type is a string, although if you can change this to whatever type you're working with (In my example backing type integer is due to an Enum being serialzed as an Int) it will map fine. Therefore as ID is an Int you can try the backing property as an Int, this will tell Episerver what type to save/load the value as. Likely both way will work but I prefer storing as the native type.

#204163
May 21, 2019 9:49
Vote:
 

I'd agree that the best approach would be to store the category as an int rather than a string given that the category ID is an int and will no doubt be used as an int though, as I mentioned above, changing a property type from string to int comes with some complexities unless you just abandon the existing string property and create a new int property with a different name.

Choosing the wrong backing type or not setting one at all can certainly cause problems in certain circumstances but, for a property type of string or int, you shouldn't need to define the backing type as Episerver automatically maps those types for you. In the case of an Enum, Episerver doesn't have a default backing type defined, hence the requirement to add the backing type attribute in that scenario. In this instance, setting the backing type of the string property to PropertyNumber will throw an error along the lines of "EPiServer.Core.TypeMismatchException: The property 'MyStringProperty' on content type 'MyPageType' is of type 'System.String' that cannot be backed by PropertyNumber, it only only supports types Int32, Enum". If the property type was changed to an int, there would be no need to define the backing type as it's automatically mapped as PropertyNumber. 

#204172
May 21, 2019 12:35
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* 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.