1

In attempting to convert a project to Core I am running into an issue.

Pre-Core System.Web.MVC.ViewDataDictionary exposed a TemplateInfo property with both a getter and a setter property. This allows us to set an HtmlFieldPrefix field that was the magic behind getting form fields in nested arrays to bind during a form POST.

We use it like this...

for (var c = 0; c < Model.Items.Count(); c++)
{
    for (var p = 0; p < Model.Items[c].ParticipantViewModels.Count; p += 1)
    {
        @Html.Partial("~/Views/Shared/_CheckoutPrices.cshtml", Model.Items[c].ParticipantViewModels[p],
            new ViewDataDictionary(Html.ViewData)
            {
                TemplateInfo = new TemplateInfo
                {
                    HtmlFieldPrefix = $"Items[{c}].ParticipantViewModels[{p}]"
                }
            })
    }
}
for (var c = 0; c < Model.UnscheduledItems.Count(); c++)
{
    for (var p = 0; p < Model.UnscheduledItems[c].ParticipantViewModels.Count; p += 1)
    {
        @Html.Partial("~/Views/Shared/_CheckoutPrices.cshtml", Model.UnscheduledItems[c].ParticipantViewModels[p],
            new ViewDataDictionary(Html.ViewData)
            {
                TemplateInfo = new TemplateInfo
                {
                    HtmlFieldPrefix = $"UnscheduledItems[{c}].ParticipantViewModels[{p}]"
                }
            })
    }
}

The same partial view is used for 'Items' and 'UnscheduledItems' but the HtmlFieldPrefix value is what gives the partial view context. The partial view can then use regular HtmlHelpers to produce the html with the proper name attribute set. In this example we use IdFor because this is a radio button but for other input types we use the helpers.

@Html.RadioButtonFor(m => Model.SelectedPriceId, Model.Prices[p].Id, new { Id = Html.IdFor(m => Model.Prices[p]) })

Which produces HTML like this..

<input id="Items_0__ParticipantViewModels_0__Prices_0_" checked="checked" name="Items[0].ParticipantViewModels[0].SelectedPriceId" type="radio" value="VFdwSk5VMUVUVEZXU0VvMVpFYzBQUT09">

The problem that I am facing is that the TemplateInfo property on the .Net Core ViewDataDictionary does not expose a setter. Source: https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.ViewFeatures/src/ViewDataDictionary.cs

Looking for a clean solution to this problem and so far can't seem to find one.

Couple questions:

  1. How is one supposed to set TemplateInfo in .Net Core?
  2. Is there a different way that we should be handling this?

Thanks in advance!

Tieson T.
  • 20,774
  • 6
  • 77
  • 92
Stephen McDowell
  • 839
  • 9
  • 21
  • please check BeginCollectionItem library for asp.net mvc, you can find a lot of articles on the web. there is a port for core as well https://github.com/saad749/BeginCollectionItemCore but i did not check it myself. – Yehor Androsov Feb 12 '20 at 21:22

1 Answers1

3

Found great solution: MVC 6 VNext how to set HtmlFieldPrefix?

Solution recap: Add an extension method like:

public static class HtmlHelpers
{
    public static Task<IHtmlContent> PartialAsync(this IHtmlHelper htmlHelper, string partialViewName, object model, string prefix)
    {
        var viewData = new ViewDataDictionary(htmlHelper.ViewData);
        var htmlPrefix = viewData.TemplateInfo.HtmlFieldPrefix;
        viewData.TemplateInfo.HtmlFieldPrefix += !Equals(htmlPrefix, string.Empty) ? $".{prefix}" : prefix;
        return htmlHelper.PartialAsync(partialViewName, model, viewData);
    }
}

And consume it like:

@await Html.PartialAsync("~/Views/Shared/_CheckoutPricesV3.cshtml", Model.Items[c].ParticipantViewModels[p], $"Items[{c}].ParticipantViewModels[{p}]")
Stephen McDowell
  • 839
  • 9
  • 21