0

I have a form with a few levels of nested data as I try and construct a form dynamically.

The idea is I have a Pool match, which is divided into many sections, which consist of many frames and I can't find a way to get the HTML form constructed in a way that submits the data properyl. The question itself is at the end of the post.

ViewModel and Models

public partial class MatchFormatsViewModel : BaseViewModel
{
    public MatchFormat MatchFormat { get; set; }
}

public class MatchFormat
{
    public long Id { get; set; }
    public League League { get; set; }
    public string Name { get; set; }
    public List<MatchFormatSection> MatchSections { get; set; }
}

public class MatchFormat
{
    public long Id { get; set; }
    public string Name { get; set; }
    public List<MatchFormatSection> MatchSections { get; set; }
}

public class MatchFormatSection
{
    public long Id { get; set; }
    public MatchFormat MatchFormat { get; set; }
    public string Name { get; set; }
    public List<MatchFormatFrame> MatchFormatFrames { get; set; }
    public int Sequence { get; set; }
    [NotMapped]
    public int RowNumber { get; set; }
}

public class MatchFormatFrame
{
    public long Id { get; set; }
    public MatchFormat MatchFormat { get; set; }
    public MatchFormatSection MatchFormatSection { get; set; }
    public string Name { get; set; }
    public int Players { get; set; }
    [NotMapped]
    public int Number { get; set; }
}

I am then using a bunch of partial views to AJAX the data around the code. The one containing the array I'm interested in is here

And the partial view around the MatchFormatFrame is a bit like this

@{
    int i = 0;
}
    
@foreach (var sectionframe in Model.MatchFormatFrames)
{
    <div class="row">
        <div class="col-3 text-center">
            <span class="text-xs my-2 mx-3"><strong>Frame @{ var frameno = i + 1; } @frameno</strong></span>
        </div>
        <div class="col-5">
            <div class="input-group mb-3">
                <input type="hidden" name="MatchFormat.MatchSections[@Model.RowNumber].MatchFormatFrames[@i].MatchFormatFrame.Number" value="@i" />
                <select name="MatchFormat.MatchSections[@Model.RowNumber].MatchFormatFrames[@i].MatchFormatFrame.Id" class="form-control form-control-sm form-select form-select-sm">
                    @foreach (var type in Model.FrameTypeSelect)
                    {
                        if (type.Value == sectionframe.FrameType.Id.ToString())
                        {
                            <option value="@type.Value" selected>@type.Text</option>
                        }
                        else
                        {
                            <option value="@type.Value">@type.Text</option>
                        }
                    }
                </select>
            </div>
        </div>
        <div class="col-2">
            <button type="button" class="btn btn-sm btn-round btn-warning btn-icon-only" onclick="RemoveSectionFrame(@i)"><i class="fas fa-trash"></i></button>

        </div>
        <div class="col-2">

        </div>
    </div>
    
    i = i + 1;
    
}

Currently, the posted data looks like this (taken from the Network tab in Chrome Dev Tools.

MatchFormat.Id: 7
MatchFormat.Name: Standard
MatchFormat.MatchSections[0].Id: 13
MatchFormat.MatchSections[0].RowNumber: 0
MatchFormat.MatchSections[0].Name: Singles 1
MatchFormat.MatchSections[0].MatchFormatFrames[0].MatchFormatFrame.Number: 0
MatchFormat.MatchSections[0].MatchFormatFrames[0].MatchFormatFrame.Id: 29
MatchFormat.MatchSections[0].MatchFormatFrames[1].MatchFormatFrame.Number: 1
MatchFormat.MatchSections[0].MatchFormatFrames[1].MatchFormatFrame.Id: 29
MatchFormat.MatchSections[0].MatchFormatFrames[2].MatchFormatFrame.Number: 2
MatchFormat.MatchSections[0].MatchFormatFrames[2].MatchFormatFrame.Id: 29
MatchFormat.MatchSections[0].MatchFormatFrames[3].MatchFormatFrame.Number: 3
MatchFormat.MatchSections[0].MatchFormatFrames[3].MatchFormatFrame.Id: 29
MatchFormat.MatchSections[0].MatchFormatFrames[4].MatchFormatFrame.Number: 4
MatchFormat.MatchSections[0].MatchFormatFrames[4].MatchFormatFrame.Id: 29
MatchFormat.MatchSections[1].Id: 14
MatchFormat.MatchSections[1].RowNumber: 1
MatchFormat.MatchSections[1].Name: Doubles
MatchFormat.MatchSections[0].MatchFormatFrames[0].MatchFormatFrame.Number: 0
MatchFormat.MatchSections[0].MatchFormatFrames[0].MatchFormatFrame.Id: 31
MatchFormat.MatchSections[0].MatchFormatFrames[1].MatchFormatFrame.Number: 1
MatchFormat.MatchSections[0].MatchFormatFrames[1].MatchFormatFrame.Id: 31
MatchFormat.MatchSections[2].Id: 15
MatchFormat.MatchSections[2].RowNumber: 2
MatchFormat.MatchSections[2].Name: Singles 2
MatchFormat.MatchSections[0].MatchFormatFrames[0].MatchFormatFrame.Number: 0
MatchFormat.MatchSections[0].MatchFormatFrames[0].MatchFormatFrame.Id: 29
MatchFormat.MatchSections[0].MatchFormatFrames[1].MatchFormatFrame.Number: 1
MatchFormat.MatchSections[0].MatchFormatFrames[1].MatchFormatFrame.Id: 29
MatchFormat.MatchSections[0].MatchFormatFrames[2].MatchFormatFrame.Number: 2
MatchFormat.MatchSections[0].MatchFormatFrames[2].MatchFormatFrame.Id: 29
MatchFormat.MatchSections[0].MatchFormatFrames[3].MatchFormatFrame.Number: 3
MatchFormat.MatchSections[0].MatchFormatFrames[3].MatchFormatFrame.Id: 29
MatchFormat.MatchSections[0].MatchFormatFrames[4].MatchFormatFrame.Number: 4
MatchFormat.MatchSections[0].MatchFormatFrames[4].MatchFormatFrame.Id: 29

However, when the data gets submitted, it does not map the MatchFormatFrames List the way I hoped. I assume its because I am submitting just an Id value so it doesn't map it.

VS view

Is there a way I can construct the HTML to submit the data in a format that will map against the List<MatchFormatFrame>?

Matthew Warr
  • 86
  • 1
  • 10
  • 31
  • Use a `for` loop rather than a `foreach` loop; then you will be able to use eg: `@Html.HiddenFor(m => m.MatchFormatFrames[index].Id)`. As it stands, I think you've got an extra `.MatchFormatFrame` in the input names: `MatchFormat.MatchSections[@Model.RowNumber].MatchFormatFrames[@i].MatchFormatFrame.Number` should be `MatchFormat.MatchSections[@Model.RowNumber].MatchFormatFrames[@i].Number` etc. – Richard Deeming Feb 10 '22 at 11:21
  • That was a ood catch, but this doesnt seem to work unfortunately `MatchFormat.MatchSections[@Model.RowNumber].MatchFormatFrames[@i].Number`. Working on the `for` loop idea at the moment – Matthew Warr Feb 10 '22 at 11:37
  • `@HtmlHiddenFor` doesn't inherit/detect it is part of a nest model, so submits the field at the top level of form data. `MatchFormatFrames[1].Id: 50` – Matthew Warr Feb 10 '22 at 11:49
  • You should be able to use `` tag helper instead of `@Html.RenderPartial` / `@Html.Partial` - see [this answer](https://stackoverflow.com/a/66951079/124386) for details. – Richard Deeming Feb 10 '22 at 12:01
  • No, still not working. `Html.HiddenFor` still creating at top level – Matthew Warr Feb 10 '22 at 12:46

0 Answers0