TyGuy96
TyGuy96

Reputation: 172

Best practice for passing an enum list to an external JS file? ASP.NET Core MVC

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?

Upvotes: 0

Views: 721

Answers (1)

Michael Wang
Michael Wang

Reputation: 4022

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

Upvotes: 1

Related Questions