Search code examples
asp.netasp.net-coretag-helpers

Inheriting from a tag helper in .NET Core


I really love the new tag helpers in .NET Core but I want to do something slightly different.

By default you can use <select asp-items=""> to make an old fashioned select list with options.

But I'd like to add a data-image-url attribute to each option so I can show a picture.

<select>  
    <option value="1" data-image-url="/picture.jpg">First Option</option>  
    <option value="2" data-image-url="/another-picture.jpg">Second Option</option> 
</select>

I created a new class that inherits from SelectListItem:

public class ProductSelectListItem : SelectListItem
{
    public string ImageUrl { get; set; }
}

but I'm having trouble figuring out how to inherit from the standard tag helper class.

Of course I could just put a for loop in the view but I'd like to see if there is a better way.

Is it possible to inherit from the standard Select tag helper class? An editor template is also an option but I don't know if it is the best/cleanest way to go in .NET Core.


Solution

  • I think we have to use custom taghelper here. And actually I didn't find a solution to inherit default select taghelper, so I create a new one.

    Related document: create tag helper, the select tag helper.

    Firstly, I prepared a new class like SelectListItem. I copied the code from SelectListItem but added new properity data_image_url:

    using Microsoft.AspNetCore.Mvc.Rendering;
    using static Microsoft.Graph.Constants;
    
    namespace WebAppMvc.Models
    {
        public class MySelectListItem 
        {
            public MySelectListItem() { }
            public MySelectListItem(string text, string value)
                : this()
            {
                Text = text;
                Value = value;
            }
            public MySelectListItem(string text, string value, bool selected)
                : this(text, value)
            {
                Selected = selected;
            }
            public MySelectListItem(string text, string value, bool selected, bool disabled)
                : this(text, value, selected)
            {
                Disabled = disabled;
            }
    
            public MySelectListItem(string text, string value, bool selected, bool disabled, string imgUrl)
                : this(text, value, selected, disabled)
            {
                data_image_url = imgUrl;
            }
    
            public bool Disabled { get; set; }
            public SelectListGroup Group { get; set; }
            public bool Selected { get; set; }
            public string Text { get; set; }
            public string Value { get; set; }
    
            public string data_image_url { get; set; }
        }
    }
    

    Then create custom taghelper MselectTagHelper:

    using Microsoft.AspNetCore.Razor.TagHelpers;
    using System.Net;
    using System.Text;
    
    namespace WebAppMvc.Models
    {
        public class MselectTagHelper : TagHelper
        {
            public List<MySelectListItem> list { get; set; }
    
            public string aspFor { get; set; }
    
        public override void Process(TagHelperContext context, TagHelperOutput output)
            {
                output.TagName = "select";
                output.Attributes.SetAttribute("id", aspFor);
                output.Attributes.SetAttribute("name", aspFor);
                var options = "";
                if (list != null) {
                    foreach (var item in list)
                    {
                        options += $@"<option value={item.Value} data-image-url={item.data_image_url}>{item.Text}</option>";
                    }
                    output.Content.SetHtmlContent(options);
                }
                
            }
        }
    }
    

    Create a viewmodel:

    public class CountryViewModel
    {
        public string Country { get; set; }
    
        public List<MySelectListItem> Countries { get; } = new List<MySelectListItem>
        {
            new MySelectListItem { Value = "MX", Text = "Mexico", data_image_url="/img.png" },
            new MySelectListItem { Value = "CA", Text = "Canada", data_image_url="/img.png" },
            new MySelectListItem { Value = "US", Text = "USA", data_image_url="/img.png"  },
        };
    }
    

    Then add @addTagHelper *, projectName in _ViewImports.cshtml.

    In the view:

    @model WebAppMvc.Models.CountryViewModel
    
    <Mselect asp-for="Country" list="Model.Countries"></Mselect>
    

    enter image description here