I have the following tag helper (this is the equivalent of saying Html.Editor):
[HtmlTargetElement("editor", Attributes = "for", TagStructure = TagStructure.WithoutEndTag)]
public class EditorTagHelper : TagHelper {
private readonly IHtmlHelper _htmlHelper;
public EditorTagHelper(IHtmlHelper htmlHelper) {
_htmlHelper = htmlHelper;
}
public ModelExpression For { get; set; }
public IDictionary<string, string> HtmlAttributes { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public string TemplateName { get; set; }
public IDictionary<string, object> ViewData { get; set; } = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
[HtmlAttributeNotBound, ViewContext]
public ViewContext ViewContext { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output) {
((IViewContextAware)_htmlHelper).Contextualize(ViewContext);
ViewData.Add("HtmlAttributes", HtmlAttributes);
output.Content.SetHtmlContent(_htmlHelper.Editor(For.Name, TemplateName, ViewData));
output.TagName = null;
}
}
Which is called like so:
<editor for="Name" view-data-test="@("Foo")" html-attributes-class="Bar" />
Here's the code for the String view template:
@model string
<input asp-for="@Model" class="form-control" />
@ViewData["Test"]
@(((IDictionary<string, string>)ViewData["HtmlAttributes"])["Class"])
This works fine but ideally I'd like to add the HtmlAttributes dictionary as attributes to the input tag helper above. Previously I would have said the following to pass the attributes to a HTML helper:
Html.TextBoxFor(m => m, new { htmlAttributes = ViewData["HtmlAttributes"] })
But what is the equivalent to pass them to a tag helper?
To create a tag helper that can work with your Dictionary you'd need to
Start by specifying the html-attributes
as a HTML attribute to the HtmlTargetElement's comma-separated Attributes list.
[HtmlTargetElement("editor", Attributes = "for, html-attributes", TagStructure = TagStructure.WithoutEndTag)]
public class EditorTagHelper : TagHelper {
Then map those to a property on the tag helper itself:
[HtmlAttributeName("html-attributes")]
public Dictionary<string, string> HtmlAttributes { get; set; }
In the process method, deconstruct and foreach through that dictionary
foreach (var (key, value) in HtmlAttributes)
{
output.Attributes.SetAttribute(key, value);
}
Use it like:
<editor for="Name" view-data-test="@("Foo")" html-attributes="@ViewData["HtmlAttributes"]" />
Edit:
If you want to only pass the ViewData to the template and then apply them to the input element inside you'd need to follow the same procedure as I told you. But you skip applying the htmlAttributes to the Editor element.
[HtmlTargetElement("input", Attributes = "for, html-attributes")]
public class InputTagHelper : TagHelper
{
public ModelExpression For { get; set; }
[HtmlAttributeName("html-attributes")]
public Dictionary<string, string> HtmlAttributes { get; set; }
public override void Process(TagHelperContext context,
TagHelperOutput output)
{
output.TagMode = TagMode.SelfClosing;
output.Attributes.SetAttribute("name", EditorFor.Name);
foreach (var (key, value) in HtmlAttributes)
{
output.Attributes.SetAttribute(key, value);
}
}
Then in your template, you can do:
@model string
<input asp-for="@Model" html-attributes="@((IDictionary<string, string>)ViewData["HtmlAttributes"])" />