aspnet / Mvc

[Archived] ASP.NET Core MVC is a model view controller framework for building dynamic web sites with clean separation of concerns, including the merged MVC, Web API, and Web Pages w/ Razor. Project moved to https://github.com/aspnet/AspNetCore
Apache License 2.0
5.62k stars 2.14k forks source link

Editor Template Tag Helper incorrectly naming name attribute #8740

Closed brackers17 closed 5 years ago

brackers17 commented 5 years ago

Is this a Bug or Feature request?:

Bug

Steps to reproduce (preferably a link to a GitHub repo with a repro project):

output.Attributes.SetAttribute("Id", AspFor.Name);

Description of the problem:

When creating my own custom tag helper I use ModelExpression.Name to set the name attribute for the element.

This works except in editor/display templates where it sets the name incorrectly to the property name instead of the prefix then the property name.

For example if you have list of person objects with age properties, the tag helper should set the name attribute to [0].Age but it just sets to Age.

Version of Microsoft.AspNetCore.Mvc or Microsoft.AspNetCore.App or Microsoft.AspNetCore.All:

mkArtakMSFT commented 5 years ago

Thanks for contacting us, @brackers17. @NTaylorMullen, can you please look into this? Thanks!

NTaylorMullen commented 5 years ago

Hey @brackers17, the ModelExpression.Name property references the relative path to the current model. So in your case when you're doing a display or editor for over a collection the relative model isn't an indexable object. To get what you're looking for you need a TagHelper that does a bit more work. For example:

public class TestModelTagHelper : TagHelper
{
    private readonly IHtmlGenerator _generator;

    public TestModelTagHelper(IHtmlGenerator generator)
    {
        _generator = generator;
    }

    public ModelExpression AspFor { get; set; }

    [ViewContext, HtmlAttributeNotBound]
    public ViewContext ViewContext { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        var id = ModelNames.CreatePropertyModelName(ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix, AspFor.Name);
        var sanitizedId = TagBuilder.CreateSanitizedId(id, _generator.IdAttributeDotReplacement);
        output.Attributes.SetAttribute("Id", sanitizedId);
    }
}
brackers17 commented 5 years ago

Hey @NTaylorMullen, that's perfect thank you! Is there a way I could have found that out myself? Without having to contact yourselves?

NTaylorMullen commented 5 years ago

Is there a way I could have found that out myself? Without having to contact yourselves?

The best way would be to inspect the code in this repo. To make things even easier though I'd suggest by adding Microsoft's public symbol server and debugging through MVC when you encounter unexpected issues such as this. 😄