0

I currently have a working setup but I would like to know if there is a better implementation.

I have a Genre.cs enum in ~/Models/Genre.cs Which is passed to the view in a view model:

public IActionResult Index()
{
    MusicFileCreateViewModel musicFileCreateViewModel = new MusicFileCreateViewModel
    {
        Genres = Enum.GetNames(typeof(Genre)), // This is a string[]
        // ...
    };
    return View(musicFileCreateViewModel);
}

Which is then handled in the view and used in the ~/js/musicFileList.js file

@model MusicFileCreateViewModel
// ...

<script>
    var Genres = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Genres));
</script>
<script src="~/js/musicFileList.js"></script>

Is there a way to improve this setup? Also, is it possible to get the enum display names instead of the actual names?

TyGuy96
  • 142
  • 1
  • 6
  • If you are not using frontend technologies, such as angular, this setup is ok. When using angular, you could create an API method that would prepare the data structures needed for the form. – Martin Staufcik Jul 07 '20 at 19:28
  • Hi, @TyGuy96, I already post the code to solve your question. It works on me. If the answer solved your question, please mark it for helping more people. If not, we may be able to continue to explore solutions. Thank you for your time and efforts. – Michael Wang Jul 10 '20 at 09:09

1 Answers1

1

To improve this setup

I agree with @Martin Staufcik, use a api to obtain enum data.

  1. Creat new action to get genres

        [Route("/genres")]
        public IList<string> GetGenres()
        {
            return EnumHelper<Genre>.GetDisplayValues(Genre.Rock);
        }
    
  2. add js to request genres

     <script type="text/javascript">
    
         $.post("/genres", null, function (data, status) {
               //data : ROCK, ELECTRONIC, SOUL, FUNK, COUNTRY
               alert(data[1]);//ELECTRONIC
         });
     </script>
    

![![enter image description here

Is it possible to get the enum display names instead of the actual names?

(1) Import EnumHelper to get Enum display names
EnumHelper.cs

public static class EnumHelper<T>
{
    public static IList<T> GetValues(Enum value)
    {
        var enumValues = new List<T>();

        foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
        {
            enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
        }
        return enumValues;
    }

    public static T Parse(string value)
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }

    public static IList<string> GetNames(Enum value)
    {
        return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
    }

    public static IList<string> GetDisplayValues(Enum value)
    {
        return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
    }

    private static string lookupResource(Type resourceManagerProvider, string resourceKey)
    {
        foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
        {
            if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
            {
                System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
                return resourceManager.GetString(resourceKey);
            }
        }

        return resourceKey; // Fallback with the key name
    }

    public static string GetDisplayValue(T value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());

        var descriptionAttributes = fieldInfo.GetCustomAttributes(
            typeof(DisplayAttribute), false) as DisplayAttribute[];

        if (descriptionAttributes[0].ResourceType != null)
            return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);

        if (descriptionAttributes == null) return string.Empty;
        return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
    }
}

(2) Add Genres to MusicFileCreateViewModel model
MusicFileCreateViewModel.cs

namespace EnumApplication.Models
{
    public enum Genre
    {
        [Display(Name = "ROCK")]
        Rock,
        [Display(Name = "ELECTRONIC")]
        Electronic,
        [Display(Name = "SOUL")]
        Soul,
        [Display(Name = "FUNK")]
        Funk,
        [Display(Name = "COUNTRY")]
        Country

    }
    public class MusicFileCreateViewModel
    {
        public int Id { get; set; }
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public IList<string> Genres { get; set; }
    }
}

(3) Set Enum names to Genres by using EnumHelper
Index action in controller

public IActionResult Index()
        {
            MusicFileCreateViewModel musicFileCreateViewModel = new MusicFileCreateViewModel
            {
                Genres = EnumHelper<Genre>.GetDisplayValues(Genre.Rock),// This is a string[]
                                                                                  // ...
            };

            return View(musicFileCreateViewModel);
        }

(4) Json Serialize
Index.cshtml

<ul>
    @foreach (var value in Model.Genres)
    {
        <li>@Html.DisplayName(value)</li>
    }
</ul>


<script type="text/javascript">
function Fn() {
    var Genres = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Genres));

}
</script>

Screenshots of Test: enter image description here

EnumHelper coded by @Hrvoje Stanisic

Michael Wang
  • 3,782
  • 1
  • 5
  • 15
  • In your `$.post("/genres", null, function (data)` function, I am getting "'data' does not exist in the current context" when being passed to the SerializeObject function. Any idea why? – TyGuy96 Jul 12 '20 at 20:10
  • Hi, sorry, my fault, No need to SerializeObject again, it's already serialized. I already update my codes and please try again. :D – Michael Wang Jul 13 '20 at 09:49