Search code examples
asp.net-coretag-helpersasp.net-core-tag-helpers

Method that expands into tag-helper


I have the following method in a cshtml file. It simply expands into two label elements. The first is a plain label element. The second however, uses a tag helper:

async Task field(string str)
{
    <label for="@str">@str</label>

    <label asp-for="@str">@str</label>
}

Here's how I have it defined in the cshtml file along with calling it once:

@{ 
    {
        async Task field(string str)
        {
            <label for="@str">@str</label>

            <label asp-for="@str">@str</label>
        }

        await field("abc");
    }
}

If I 'view source' on the result, I see the following:

<label for="abc">abc</label>
<label for="str">abc</label>

Note that the @str argument was properly passed and used in the first case but was not in the second case. So it seems that there's an issue in passing the argument to the tag-helper variant here.

Any suggestions on how to resolve this?


Solution

  • In my opinion, the argument has been passed the tag-helper variant successfully. But the the label asp-for attribute will be rendered as the for attribute with asp-for ModelExpression's name value(str) not the value ModelExpression's model(abc).

    According to the label taghelper source codes, you could find the tag helper will call the Generator.GenerateLabel method to generate the label tag html content.

    The Generator.GenerateLabel has five parameters, the third parameter expression is used to generate the label's for attribute.

     var tagBuilder = Generator.GenerateLabel(
            ViewContext,
            For.ModelExplorer,
            For.Name,
            labelText: null,
            htmlAttributes: null);
    

    enter image description here

    If you want to show the str value for the for attribute, you should create a custom lable labeltaghelper.

    More details, you could refer to below codes:

    [HtmlTargetElement("label", Attributes = "asp-for")]
    public class ExtendedAspForTagHelper:LabelTagHelper
    {
        public ExtendedAspForTagHelper(IHtmlGenerator generator)
            : base(generator)
        {
        }
        public override int Order => -10000;
    
    
        //public override void Process(TagHelperContext context, TagHelperOutput output)
        //{
        //    base.Process(context, output);
    
    
    
        //    if (!output.Attributes.TryGetAttribute("maxlength", out TagHelperAttribute maxLengthAttribute))
        //    {
        //        return;
        //    }
    
    
    
        //    var description = $"Only <b>{maxLengthAttribute.Value}</b> characters allowed!";
        //    output.PostElement.AppendHtml(description);
        //}
        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
    
    
    
    
            if (output == null)
            {
                throw new ArgumentNullException(nameof(output));
            }
    
    
    
    
            var tagBuilder = Generator.GenerateLabel(
                ViewContext,
                For.ModelExplorer,
                For.Model.ToString(),
                labelText: null,
                htmlAttributes: null);
    
    
    
    
            if (tagBuilder != null)
            {
                output.MergeAttributes(tagBuilder);
    
    
    
    
                // Do not update the content if another tag helper targeting this element has already done so.
                if (!output.IsContentModified)
                {
                    // We check for whitespace to detect scenarios such as:
                    // <label for="Name">
                    // </label>
                    var childContent = await output.GetChildContentAsync();
                    if (childContent.IsEmptyOrWhiteSpace)
                    {
                        // Provide default label text (if any) since there was nothing useful in the Razor source.
                        if (tagBuilder.HasInnerHtml)
                        {
                            output.Content.SetHtmlContent(tagBuilder.InnerHtml);
                        }
                    }
                    else
                    {
                        output.Content.SetHtmlContent(childContent);
                    }
                }
            }
        }
    }
    

    Improt this taghelper in _ViewImports.cshtml

    @addTagHelper *,[yournamespace]
    

    Result:

    enter image description here