ASP.NET Core - есть ли способ визуализировать группу элементов, каждый из которых использует настраиваемые помощники по тегам?

В своем проекте я заметил, что все поля моей формы следуют одному и тому же шаблону. Типичный пример:

<div class="col-x-x">
  <label asp-for="Property"></label>
  <span message="description">
  <input asp-for="Property" />
  <span asp-validation-for="Property"></span>
</div>

Я хотел бы иметь какой-то способ сгруппировать этот код, чтобы я просто передал ему свойство модели, и он выводил правильный HTML. например.:

<form-field for="Property" ...>

or

@Html.StringFormField(...)

Проблема, с которой я сталкиваюсь, заключается в том, что какой бы метод я ни пробовал, выводимый html - это исходный html, указанный выше, а не html, созданный с помощью помощников тегов. Я пробовал оба метода, и ни один из них не увенчался успехом. Кроме того, я попытался создать функцию бритвы, но все мои попытки не компилируются, и я не могу заставить работать частичное представление, так как я не смог найти способ получить информацию о свойстве после передачи строки в Посмотреть.

Моя последняя попытка заключалась в использовании помощника по тегу, однако здесь была та же проблема, о которой говорилось ранее. Последняя версия кода выглядит следующим образом:

[HtmlTargetElement("form-field", Attributes = "for")]
public class FormFieldTagHelper : TagHelper
{
    [HtmlAttributeName("for")]
    public ModelExpression For { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "div";
        output.TagMode = TagMode.StartTagAndEndTag;

        var contentBuilder = new HtmlContentBuilder();

        contentBuilder.AppendHtmlLine($"<label asp-for=\"{For}\"></label>");
        contentBuilder.AppendHtmlLine($"<span message=\"description.\"></span>");
        contentBuilder.AppendHtmlLine($"<input asp-for=\"{For}\"/>");
        contentBuilder.AppendHtmlLine($"<span asp-validation-for=\"{For}\"/></span>");

        output.Content.SetHtmlContent(contentBuilder);
    }
}

Существует проблема для решения этой проблемы (без решения), которая предположил, что порядок импорта был потенциальной проблемой, поэтому мой импорт выглядит следующим образом:

@addTagHelper Project.Web.Features.Shared.*, Project.Web
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Приветствуется любое решение, будь то помощник по тегу или другой метод.


person ArcticFox    schedule 18.01.2020    source источник


Ответы (2)


Вы можете использовать IHtmlGenerator, чтобы сгенерировать эти элементы, см. мой демонстрационный код ниже:

[HtmlTargetElement("form-field", Attributes = "for")]
public class FormFieldTagHelper : TagHelper
{
    [HtmlAttributeName("for")]
    public ModelExpression For { get; set; }

    private readonly IHtmlGenerator _generator;

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

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

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        using (var writer = new StringWriter())
        {
            writer.Write(@"<div class=""form-group"">");

            var label = _generator.GenerateLabel(
                            ViewContext,
                            For.ModelExplorer,
                            For.Name, null,
                            new { @class = "control-label" });

            label.WriteTo(writer, NullHtmlEncoder.Default);
            writer.Write(@"<span message=""description.""></span>");

            var textArea = _generator.GenerateTextBox(ViewContext,
                                For.ModelExplorer,
                                For.Name,
                                For.Model,
                                null,
                                new { @class = "form-control" });

            textArea.WriteTo(writer, NullHtmlEncoder.Default);

            var validationMsg = _generator.GenerateValidationMessage(
                                    ViewContext,
                                    For.ModelExplorer,
                                    For.Name,
                                    null,
                                    ViewContext.ValidationMessageElement,
                                    new { @class = "text-danger" });

            validationMsg.WriteTo(writer, NullHtmlEncoder.Default);

            writer.Write(@"</div>");

            output.Content.SetHtmlContent(writer.ToString());

        }
    }
}

Вид:

 <form-field for="ManagerName"></form-field>

Результат:

введите описание изображения здесь

person Ryan    schedule 20.01.2020
comment
Это действительно хорошее предложение, однако я не упомянул (и изменил заголовок), что все помощники тегов являются настраиваемыми, поэтому для использования этого метода потребуются дополнительные функции html для дублирования функций помощников тегов. - person ArcticFox; 20.01.2020

Кажется, что самый простой способ сделать это без дублирования вспомогательного кода настраиваемого тега с помощью генератора html - это просто создать новые экземпляры вспомогательных функций настраиваемого тега из нового помощника тега.

e.g.

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)   
{
    output.TagName = "div";
    output.TagMode = TagMode.StartTagAndEndTag;

    //create label tag
    LabelForTagHelper labelTagHelper = new LabelForTagHelper(ValidatorFactory)
    {
        For = this.For,
        IgnoreRequired = this.IgnoreRequired
    };

    TagHelperOutput labelOutput = new TagHelperOutput(
        tagName: tagName,
        attributes: attributes ?? new TagHelperAttributeList(),
        getChildContentAsync: (s, t) =>
        {
            return Task.Factory.StartNew<TagHelperContent>(() => new DefaultTagHelperContent());
        }
    );

    var labelElement = await labelTagHelper.ProcessAsync(context, labelOutput);

    output.Content.AppendHtml(labelElement );

    //repeat for other tags
}
person ArcticFox    schedule 20.01.2020