Skip to content

Instantly share code, notes, and snippets.

@nickalbrecht
Last active July 3, 2020 00:31
Show Gist options
  • Save nickalbrecht/6147ebb642543726ef1355c526333f55 to your computer and use it in GitHub Desktop.
Save nickalbrecht/6147ebb642543726ef1355c526333f55 to your computer and use it in GitHub Desktop.
Variation on my CollectionEditingHtmlExtensions gist to use TagHelper instead.
[HtmlTargetElement("CollectionItem")]
public class CollectionItemTagHelper : TagHelper
{
private readonly IHtmlHelper htmlHelper;
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
public CollectionItemTagHelper(IHtmlHelper htmlHelper)
{
this.htmlHelper = htmlHelper;
}
[HtmlAttributeName("name")]
public string CollectionName { get; set; }
[HtmlAttributeName("index")]
public string IndexValue { get; set; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (CollectionName == null)
throw new ArgumentNullException(nameof(CollectionName), "CollectionName is null");
if (string.IsNullOrEmpty(IndexValue))
throw new ArgumentException("IndexValue is null or empty", nameof(IndexValue));
//Needed to initialize the htmlHelper
(htmlHelper as IViewContextAware).Contextualize(ViewContext);
//suppress rendering of the TagHelper element itself
output.TagName = null;
//a hidden <input> element to hold the current index value passed in
var indexField = new TagBuilder("input");
indexField.MergeAttributes(new Dictionary<string, string>() {
{ "name", htmlHelper.ViewData.TemplateInfo.GetFullHtmlFieldName(CollectionName != string.Empty ? $"{CollectionName}.Index" : "Index") },
{ "value", IndexValue },
{ "type", "hidden" },
{ "autocomplete", "off" }
});
//Write the hidden <input> element
output.PreElement.AppendHtml(indexField);
using (new CollectionItemNamePrefixScope(htmlHelper.ViewData.TemplateInfo, htmlHelper.ViewData.TemplateInfo.GetFullHtmlFieldName($"{CollectionName}[{IndexValue}]")))
{
output.Content.SetHtmlContent(await output.GetChildContentAsync());
}
}
private class CollectionItemNamePrefixScope : IDisposable
{
private readonly TemplateInfo _templateInfo;
private readonly string _previousPrefix;
public CollectionItemNamePrefixScope(TemplateInfo templateInfo, string collectionItemName)
{
_templateInfo = templateInfo;
_previousPrefix = templateInfo.HtmlFieldPrefix;
templateInfo.HtmlFieldPrefix = collectionItemName;
}
public void Dispose()
{
_templateInfo.HtmlFieldPrefix = _previousPrefix;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment