I have used following code in multiple views:
<input asp-for="@Model.Tags" class="form-control" data-provider="tagseditor" />
<!-- some additional code will be added in future -->
and I would like to take this code and create reusable TagHelper (or alternativelly ViewComponent) from it so I will use it like this:
<tags-editor for="@Model.Tags" />
However I'm not able to pass the ModelExpression from my custom tag helper into underlying InputTagHelper.
I'm getting:
ArgumentException: The name of an HTML field cannot be null or empty. Instead use methods Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper.Editor or Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper`1.EditorFor with a non-empty htmlFieldName argument value. Parameter name: expression
On this this line: _htmlHelper.PartialAsync
<!-- Views/Shared/TagHelpers/TagsEditor -->
@model ModelExpression
<input asp-for="@Model" class="form-control" data-provider="tagseditor" />
[HtmlTargetElement("tags-editor", Attributes = "for", TagStructure = TagStructure.WithoutEndTag)]
public class TagsEditorTagHelper : TagHelper
{
private HtmlHelper _htmlHelper;
private HtmlEncoder _htmlEncoder;
public TagsEditorTagHelper(IHtmlHelper htmlHelper, HtmlEncoder htmlEncoder)
{
_htmlHelper = htmlHelper as HtmlHelper;
_htmlEncoder = htmlEncoder;
}
[HtmlAttributeName("for")]
public ModelExpression For { get; set; }
[ViewContext]
public ViewContext ViewContext
{
set => _htmlHelper.Contextualize(value);
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = null;
//exception thrown here:
var partial = await _htmlHelper.PartialAsync("TagHelpers/TagsEditor", For);
var writer = new StringWriter();
partial.WriteTo(writer, _htmlEncoder);
output.Content.SetHtmlContent(writer.ToString());
}
}
The gist of the problem comes from the fact that the ModelExpression is not a model in itself. You'll have to call its Model property.
So in your partial view:
<!-- Views/Shared/TagHelpers/TagsEditor -->
@model ModelExpression
<input asp-for="@Model.Model" class="form-control" data-provider="tagseditor" />
Then, you can't set the output tag name to null, because that will generate a <null></null> tag in your view. I suggest you change it to "div", or whatever container works for you.
Finally, because the input tag is self closing, you'll need to change the output tag mode to TagMode.StartTagAndEndTag to force generating <div></div> instead of just <div/>.
All told, the ProcessAsync method becomes:
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "div";
output.TagMode = TagMode.StartTagAndEndTag;
var partial = await _htmlHelper.PartialAsync("TagHelpers/TagsEditor", For);
var writer = new StringWriter();
partial.WriteTo(writer, _htmlEncoder);
output.Content.SetHtmlContent(writer.ToString());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With