Issue when using 'PropertyDictionaryMultiple' as a backing type for a block in Commerce

Vote:
 

Hi,

I have created a Block which I am using on a Commerce Product Node and am running into issues when adding a property and setting the backing type to be 'PropertyDictionaryMultiple'.  The editor is not rendering correctly, I am just seeing a text input, rather than a collection of check boxes.

When I move the same property down to the Product, it is rendered as expected.

Example below

[BackingType(typeof(PropertyDictionaryMultiple))]
[Display(Name = "Connectors2", Order = 7)]
[CultureSpecific]
public virtual PropertyList<string> Connectors2 { get; set; }

I am using Commerce '13.6.0'.

Looking at other posts it seems that this was reported and fixed in commerce 12.

Thanks

#206851
Sep 02, 2019 11:23
Vote:
 

The editor for PropertyDictionaryMultiple is registered for TargetType = typeof(ItemCollection<string>), so you have two options:

  • Change your property to ItemCollection<string> instead of PropertyList<string> (preferred) 
  • Add a new EditorDescriptor that target PropertyList<string>
#206853
Sep 02, 2019 11:39
Vote:
 

Hi Quan,

Thanks for the quick response, but unfortunately it doesn't work.  I have also reproduced the issue in quick silver, example code below

Works as expected (Items rendered out as a collection of checkboxes)

[CatalogContentType(
GUID = "550ebcfc-c989-4272-8f94-c6d079f56181",
MetaClassName = "FashionProduct",
DisplayName = "Fashion product",
Description = "Display fashion product")]
public class FashionProduct : ProductContent
{

...

[Searchable]
[IncludeInDefaultSearch]
[BackingType(typeof(PropertyDictionaryMultiple))]
[Display(Name = "Available Colors", Order = 6)]
public virtual ItemCollection<string> AvailableColors { get; set; }

}

Failing example (Text input displayed)

[CatalogContentType(
GUID = "550ebcfc-c989-4272-8f94-c6d079f56181",
MetaClassName = "FashionProduct",
DisplayName = "Fashion product",
Description = "Display fashion product")]
public class FashionProduct : ProductContent
{

public virtual SpecificationsBlock Specifications { get; set; }

}

[ContentType(
DisplayName = "Specifications Block",
GUID = "73E57D6A-9196-4C84-B76C-8CE397C5CC04",
Description = "Specifications Block",
AvailableInEditMode = false)]
public class SpecificationsBlock : BlockData
{

...


[Searchable]
[IncludeInDefaultSearch]
[BackingType(typeof(PropertyDictionaryMultiple))]
[Display(Name = "Available Colors", Order = 6)]
public virtual ItemCollection<string> AvailableColors { get; set; }


}

#206857
Sep 02, 2019 12:56
Vote:
 

Hmm, you would need this attribute as well

[UIHint(SystemUiHint.DictionaryMultipleSelector)]

By using ItemCollection<string> the framework will add the UIHint for you, but not on a nested property like that 

#206858
Sep 02, 2019 13:17
Vote:
 

Hi Quan,

Adding this attribute works, but exposes a bug I think. 

When the property is added to the block, a metadata/dictionary is created with the name 'EpiBlock_<Blockname>_<PropertyName>'  But the editor control tries to load the data, it expects to use the <PropertyName>.

In the example above you can see the metadata created by the system, and the one I created to stop the editor crashing.

Logs below

System.ArgumentException: Could not load the meta field 'Connectors'.
at EPiServer.Commerce.Shell.UIDescriptors.EditorDescriptors.SelectionFactories.DictionarySelectionFactory.LoadDictionary(String metaFieldName)
at EPiServer.Commerce.Shell.UIDescriptors.EditorDescriptors.SelectionFactories.DictionarySelectionFactory.<GetSelections>d__1.MoveNext()
at EPiServer.Shell.UI.Rest.DefaultMetadataStoreModelCreator.GetSelections(ExtendedMetadata metadata, MetadataStoreModel metadataDTO, ISelectionFactory[] selectionFactories)
at EPiServer.Shell.UI.Rest.DefaultMetadataStoreModelCreator.CreateFromModelMetadata(ExtendedMetadata metadata, LocalizationService localizationService, UIDescriptorRegistry uiDescriptorRegistry, ISelectionFactory[] selectionFactories, Boolean alwaysCreateChildProperties)
at EPiServer.Shell.UI.Rest.DefaultMetadataStoreModelCreator.ExtractMetadataFromProperties(ExtendedMetadata metadata, MetadataStoreModel MetadataStoreModel, LocalizationService localizationService, UIDescriptorRegistry uiDescriptorRegistry, ISelectionFactory[] selectionFactories)
at EPiServer.Shell.UI.Rest.DefaultMetadataStoreModelCreator.CreateFromModelMetadata(ExtendedMetadata metadata, LocalizationService localizationService, UIDescriptorRegistry uiDescriptorRegistry, ISelectionFactory[] selectionFactories, Boolean alwaysCreateChildProperties)
at EPiServer.Shell.UI.Rest.DefaultMetadataStoreModelCreator.ExtractMetadataFromProperties(ExtendedMetadata metadata, MetadataStoreModel MetadataStoreModel, LocalizationService localizationService, UIDescriptorRegistry uiDescriptorRegistry, ISelectionFactory[] selectionFactories)
at EPiServer.Shell.UI.Rest.DefaultMetadataStoreModelCreator.CreateFromModelMetadata(ExtendedMetadata metadata, LocalizationService localizationService, UIDescriptorRegistry uiDescriptorRegistry, ISelectionFactory[] selectionFactories, Boolean alwaysCreateChildProperties)
at EPiServer.Shell.UI.Rest.DefaultMetadataStoreModelCreator.Create(ModelMetadata metadata)
at EPiServer.Shell.UI.Rest.MetadataStore.Get(String id, String modelAccessor)
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c.<BeginInvokeSynchronousActionMethod>b__9_0(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass11_0.<InvokeActionMethodFilterAsynchronouslyRecursive>b__0()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3_6.<BeginInvokeAction>b__4()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3_1.<BeginInvokeAction>b__1(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult)
at EPiServer.Shell.Services.Rest.RestControllerBase.EndExecute(IAsyncResult asyncResult)
#206874
Sep 02, 2019 22:07
Vote:
 

True. Now it's probably a déjà vu, but that was probably the reason that we didn't add the UIHint automatically for the nested properties... I will need to check with the team 

#206999
Sep 06, 2019 11:11
Vote:
 

I checked with the team, the decision was made some time ago that we only support the dictionary types in block at API level, but not UI level, due to complexity. So ... 

#207000
Sep 06, 2019 11:23
Vote:
 

Hi Quan,

Is this on the backlog to get resolved?

It may be worth updating the documentation around the limitations of blocks within commerce. There are a number of areas where the behaviour isn't the same as the CMS.

Thanks

#207325
Sep 17, 2019 9:33