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

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

<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" ...>

или

@Html.StringFormField(...)

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

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

[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

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

Ответы [ 2 ]

2 голосов
/ 20 января 2020

Вы можете использовать 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>

Результат:

enter image description here

0 голосов
/ 20 января 2020

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

например

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
}
...