Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Martin Rud 255 posts 986 karma points c-trib
    15 days ago
    Martin Rud
    0

    How to render User-defined List with Umbraco.Community.Contentment.DataList?

    I am using Umbraco.Community.Contentment.DataList property editor and have this setup:

    enter image description here

    And an editor has selected some items:

    enter image description here

    I want to render icon, name and value in the frontend, but I can only get the value part, since the below code only renders:

    <ul class="product-icons">
            <li>max650</li>
            <li>max900</li>
    </ul> 
    

    My code:

    var productIconsLoads = Model.Value<IEnumerable<string>>("productIconsLoads");
    if(productIconsLoads != null)
    {
        <ul class="product-icons">
            @foreach (var iconLoad in productIconsLoads)
            {
                <li>@iconLoad</li>
            }
        </ul>
    }
    

    How can I get the properties on each iconLoad item?

  • Andy Boot 48 posts 190 karma points MVP
    15 days ago
    Andy Boot
    0

    Hi Martin,

    I would approach this at a more code first level.

    Rather than storing the set of options against a user-defined list, I'd create my own custom data source containing the same data.

    See docs on how to create this: https://github.com/leekelleher/umbraco-contentment/blob/develop/docs/editors/data-list.md#how-to-extend-this-with-my-own-stuff

    The GetItems() method returns IEnumerable<DataListItem>. DataListItem contains your Name, Value, Icon & Description.

    You'll probably want to centralise this collection of DataListItem objects within a class which is accessible via both your custom data source and your own code. Your code would just need to search through the collection to get the correct object (e.g. collection.FirstOrDefault(x => x.Value.InvariantEquals(value), value in this case could be max650).

    I hope this helps gives you an alternate perspective with the approach to take on this.

    Regards,

    Andy

  • Martin Rud 255 posts 986 karma points c-trib
    14 days ago
    Martin Rud
    0

    I tried with the example code that is provided out there, just to make a PoC:

    public class TimeZoneDataSource : IDataListSource
    {
        public string Name => "Time zones";
    
        public string Description => "Data source for all the time zones.";
    
        public string Icon => "icon-globe";
    
        public string Group => "Custom";
    
        public OverlaySize OverlaySize => OverlaySize.Small;
    
        public Dictionary<string, object> DefaultValues => default;
    
        public IEnumerable<ConfigurationField> Fields => default;
    
        public IEnumerable<DataListItem> GetItems(Dictionary<string, object> config)
        {
            var items = new List<DataListItem>();
    
            foreach (var timezone in TimeZoneInfo.GetSystemTimeZones())
            {
                items.Add(new DataListItem
                {
                    Name = timezone.DisplayName,
                    Value = timezone.Id
                });
            }
    
            return items;
        }
    }
    

    But I got some missing namespaces and ended up using "Umbraco Content" as data source. That works fine, but feels like a bit of overkill, though.

    If you could point me in a direction with some more code, then you are welcome. But I can live with the "Umbraco content" solution 😊

  • Andy Boot 48 posts 190 karma points MVP
    14 days ago
    Andy Boot
    101

    Hi Martin,

    Sure no worries, I've put together a raw and simple proof of concept based upon the code and configuration within your original post. It shows how you can centralise your options which can be consumed by both a Contentment data source and your own code.

    MyDataSourceItems.cs:

    using Umbraco.Community.Contentment.DataEditors;
    using Umbraco.Extensions;
    
    namespace MyProject
    {
        public class MyDataSourceItems
        {
            public List<DataListItem> Items { get; set; } = new List<DataListItem>() { 
                new DataListItem() { Icon = "icon-stop color-yellow", Name = "Max 650", Value = "max650" },
                new DataListItem() { Icon = "icon-stop color-orange", Name = "Max 900", Value = "max900" },
                new DataListItem() { Icon = "icon-stop color-red", Name = "Max 1100", Value = "max1100" }
            };
    
            public DataListItem? GetDataListItem(string value)
            {
                return Items.FirstOrDefault(x => x.Value.InvariantEquals(value) == true);
            }
        }
    }
    

    MyDataSource.cs:

    using Umbraco.Cms.Core.PropertyEditors;
    using Umbraco.Community.Contentment.DataEditors;
    
    namespace MyProject
    {
        public class MyDataSource : IDataListSource
        {
            public string Name => "My Contentment Data Source";
    
            public string Description => "Data source for my items.";
    
            public string Icon => "icon-stop";
    
            public string Group => "Custom";
    
            public OverlaySize OverlaySize => OverlaySize.Small;
    
            public Dictionary<string, object> DefaultValues => default;
    
            public IEnumerable<ConfigurationField> Fields => default;
    
            public IEnumerable<DataListItem> GetItems(Dictionary<string, object> config)
            {
                var myDataSourceItems = new MyDataSourceItems();
                return myDataSourceItems.Items;
            }
        }
    }
    

    MyRazorView.cshtml:

    @{
        var myDataSourceItems = new MyDataSourceItems();
        var productIconsLoads = (Model.Value<IEnumerable<string>>("productIconsLoads")).Select(x => myDataSourceItems.GetDataListItem(x));
        if (productIconsLoads != null)
        {
            <ul class="product-icons">
                @foreach (var iconLoad in productIconsLoads.Where(x => x != null))
                {
                    <li>
                        <ul>
                            <li>Icon: @iconLoad.Icon</li>
                            <li>Name: @iconLoad.Name</li>
                            <li>Value: @iconLoad.Value</li>
                        </ul>
                    </li>
                }
            </ul>
        }
    }
    

    I hope this helps piece together any confusion you may have had.

    Let me know if you have any more questions πŸ™‚

  • Martin Rud 255 posts 986 karma points c-trib
    1 week ago
    Martin Rud
    0

    Thanks; that works really great and much simpler that creating a lot of document types and content nodes😊

    Just one question more: Instead of creating source and data list content by code, isn't it possible to use the data souce "User-defined List":

    enter image description here

  • Andy Boot 48 posts 190 karma points MVP
    1 week ago
    Andy Boot
    0

    Great! Glad it helps.

    You could continue to use a user defined list, however you'll then have two places to maintain your list of options. Having it all in one place means less maintenance.

  • Martin Rud 255 posts 986 karma points c-trib
    1 week ago
    Martin Rud
    0

    Yes, but then I can add/remove options from backend without having to change and deploy code, right?

  • Andy Boot 48 posts 190 karma points MVP
    1 week ago
    Andy Boot
    0

    You could, but how will your frontend code know how to handle changes?

    For example, if you added a new option named "Max 2000" via the backoffice (within the user-defined list), your razor code won't know how to parse it and therefore skip it.

    Or... let's go with a more basic change, such as changing an icon colour. The colour would be accurate in the backoffice, but the frontend will still have the old colour given the two sources aren't interlinked.

  • Martin Rud 255 posts 986 karma points c-trib
    1 week ago
    Martin Rud
    0

    I thought that was how the data source "User-defined List" worked and was made for:

    As I showed in my initial post the frontent does know what the values of each item are. Problem for me was that it seems to only know of the values, not other properties like name, description and icon.

  • Andy Boot 48 posts 190 karma points MVP
    1 week ago
    Andy Boot
    0

    Contentment Data List is a UI rich alternative to the out of the box alternatives supplied by Umbraco such as the dropdown, checkbox list, radio button list, etc property editors.

    The Umbraco property editors offer very basic functionality where only predefined values can be supplied. When an editor see's the options on a property they're seeing the same value which is given to the code. This is fine for some things, but limited for others.

    The Contentment Data List offers similar deliverables, except instead of the predefined values being just values, you have the added ability to give each option names, descriptions, icons and of course, the value itself. Having these additional attributes per option gives your editors a nicer editing experience. But the important thing to note is that your code will only receive the value. As you've already discovered.

    Whether you use a User-defined List, custom data source or even the supplied '.NET Countries (ISO 3166-1)' data sources, the format of the data is still given to the Contentment Data List in the exact same format:

    [
      {
        "description": "",
        "icon": "",
        "name": "",
        "value": ""
      },
      {
         ...
      },
      ...
    ]
    

    A User-defined List just manually populates this array from the CMS, whereas the others are code generated. The important thing to consider is that only the value will be presented to your code.

    The code I supplied before was giving you the ability to define your options from a single source (MyDataSourceItems) which is consumed by your Contentment Data List and your code.

    I hope this helps clarify things.

  • Martin Rud 255 posts 986 karma points c-trib
    1 week ago
    Martin Rud
    0

    Hi Andy,

    Thanks for your thorough explanation. It makes good sense. I did not realize that description, icon and name are just for use in backend. 😊

Please Sign in or register to post replies

Write your reply to:

Draft