locked
Dynamic shorthand element tag helper RRS feed

  • Question

  • User2027810965 posted

    I'm working with .net Core 2.2 and trying to set the element tag at run time using a property on the view model class so that a tag helper can modify the html and it looks like the tag helper isn't triggered.

    For testing purposes I have the following class in my view model:

    public static IQueryable<DynamicField> IronMan => new List<DynamicField>
    {
    new DynamicField { DisplayName = "Key", TypeCode = "strong", SortOrder = 1, Value = "11132", },
    new DynamicField { DisplayName = "FirstName", TypeCode = "string10", SortOrder = 2, Value = "Ironman", Tags = new List<string> {"Tag1", "Tag2"}},
    new DynamicField { DisplayName = "Age", TypeCode = "number", SortOrder = 3, Value = "35", Tags = new List<string> {"Tag1", "Tag3"}},
    new DynamicField { DisplayName = "MarvelVerse", TypeCode = "yesno", SortOrder = 4, Value = "1", Tags = new List<string> {"TagYesNo" }}
    }.AsQueryable<DynamicField>();

    I have the following tag helper setup:

    using Microsoft.AspNetCore.Razor.TagHelpers;
    
    namespace DynamicUi.Infrastructure.TagHelpers.View
    {
    
        public class Strong : TagHelper
        {
            public override void Process(TagHelperContext context, TagHelperOutput output)
            {
                output.TagName = "div";
                output.TagMode = TagMode.StartTagAndEndTag;
                output.Attributes.SetAttribute("class", "col-sm ");
                output.PreContent.SetHtmlContent("<b>");
                output.PostContent.SetHtmlContent("</b>");
            }
        }
    }

    In my page, if I use the tag helper directly, it is applied correctly:

    <div>
        <p>tag hard-coded</p>
        <div class="container">
            @foreach (var dynamicField in FakeAPIRepository.IronMan)
            {
                <div class="row">
                    <strong>@dynamicField.DisplayName</strong>
                    <div class="col-sm">@dynamicField.Value</div>
                    <div class="col-sm">@dynamicField.TypeCode</div>
                    <div class="col-sm">@dynamicField.SortOrder</div>
                </div>
                }
        </div>
    </div>

    Result:

    <div>
        <p>tag hard-coded</p>
        <div class="container">
                <div class="row">
                    <div class="col-sm "><b>Key</b></div>
                    <div class="col-sm">11132</div>
                    <div class="col-sm">strong</div>
                    <div class="col-sm">1</div>
                </div>
                <div class="row">
                    <div class="col-sm "><b>FirstName</b></div>
                    <div class="col-sm">Ironman</div>
                    <div class="col-sm">string10</div>
                    <div class="col-sm">2</div>
                </div>
                <div class="row">
                    <div class="col-sm "><b>Age</b></div>
                    <div class="col-sm">35</div>
                    <div class="col-sm">number</div>
                    <div class="col-sm">3</div>
                </div>
                <div class="row">
                    <div class="col-sm "><b>MarvelVerse</b></div>
                    <div class="col-sm">1</div>
                    <div class="col-sm">yesno</div>
                    <div class="col-sm">4</div>
                </div>
        </div>
    </div>

    However, what I would like to do is set the element type at run-time based on the data.  What I've tried is:

    <div>
        <p>tag dynamically used</p>
        <div class="container">
            @foreach (var dynamicField in FakeAPIRepository.IronMan)
            {
                <div class="row">
                    <@dynamicField.TypeCode>@dynamicField.DisplayName</@dynamicField.TypeCode>
                    <div class="col-sm">@dynamicField.Value</div>
                    <div class="col-sm">@dynamicField.TypeCode</div>
                    <div class="col-sm">@dynamicField.SortOrder</div>
                </div>
            }
        </div>
    </div>

    But the strong tag helper doesn't transform the element into the div like it does when I use the tag helper explicitly and I end up with this:

    <div>
        <p>tag dynamically used</p>
        <div class="container">
                <div class="row">
                    <strong>Key</@dynamicField.TypeCode>
                    <div class="col-sm">11132</div>
                    <div class="col-sm">strong</div>
                    <div class="col-sm">1</div>
                </div>
                <div class="row">
                    <string10>FirstName</@dynamicField.TypeCode>
                    <div class="col-sm">Ironman</div>
                    <div class="col-sm">string10</div>
                    <div class="col-sm">2</div>
                </div>
                <div class="row">
                    <number>Age</@dynamicField.TypeCode>
                    <div class="col-sm">35</div>
                    <div class="col-sm">number</div>
                    <div class="col-sm">3</div>
                </div>
                <div class="row">
                    <yesno>MarvelVerse</@dynamicField.TypeCode>
                    <div class="col-sm">1</div>
                    <div class="col-sm">yesno</div>
                    <div class="col-sm">4</div>
                </div>
        </div>
    </div>

    I've also tried it with a self-closing tag since the closing tag wasn't creating properly:

    <div>
        <p>tag dynamically used</p>
        <div class="container">
            @foreach (var dynamicField in FakeAPIRepository.IronMan)
            {
                <div class="row">
                    <@dynamicField.TypeCode text=@dynamicField.DisplayName />
                    <div class="col-sm">@dynamicField.Value</div>
                    <div class="col-sm">@dynamicField.TypeCode</div>
                    <div class="col-sm">@dynamicField.SortOrder</div>
                </div>
            }
        </div>
    </div>

    But that didn't work either.

    Is there a way to do this without adding a huge case statement that has each TypeCode we will have in a partial/vc to generate the html?

    Thanks

    SleepyBadger

    Tuesday, August 18, 2020 12:40 PM

All replies

  • User-17257777 posted

    Hi SleepyBadger,

    I think you can use a Condition Tag Helper.

    [HtmlTargetElement(Attributes = nameof(Condition))]
    public class Strong : TagHelper
    {
        public string Condition { get; set; }
    
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if(Condition == "Strong") 
            { 
                output.TagName = "div";
                output.TagMode = TagMode.StartTagAndEndTag;
                output.Attributes.SetAttribute("class", "col-sm ");
                output.PreContent.SetHtmlContent("<b>");
                output.PostContent.SetHtmlContent("</b>");
            }

    //...other condition } }

    And in the page:

    @foreach (var dynamicField in Model)
    {
        <div class="row">
            <strong condition="@dynamicField.TypeCode">@dynamicField.DisplayName</strong>
            <div class="col-sm">@dynamicField.Value</div>
            <div class="col-sm">@dynamicField.TypeCode</div>
            <div class="col-sm">@dynamicField.SortOrder</div>
        </div>
    }

    Best Regards,

    Jiadong Meng

    Wednesday, August 19, 2020 9:48 AM
  • User2027810965 posted

    Thanks Jiadong Meng,

    We will eventually have 100's of dynamicField type codes and was hoping to avoid a giant case or 100's of if statements since with your example, I'd need an if for each possible type code.

    SleepyBadger

    Wednesday, August 19, 2020 10:48 AM