Razor MVC: Как я могу правильно рекурсивно привязать (и отредактировать) вложенный список к элементам html?

#c# #recursion #razor #asp.net-core-mvc #model-binding

Вопрос:

Мне трудно отправить обратно свою модель контроллеру. С тем, что я сделал, я получаю только корневой элемент и один дочерний элемент, отправленный обратно на контроллер. Я знаю, что проблема в том, что с рекурсивной функцией все html-элементы в конечном итоге имеют одно и то же имя, но как я могу это исправить? Поскольку я не знаю, сколько уровней будет в моем списке, я не могу использовать их для циклов :/

Это мой класс:

 public class BilletesViewModel
{
    public string Id { get; set; }
    public string IdPadre { get; set; }
    public string IdHijo { get; set; }
    public int Nivel { get; set; }
    public string Familia { get; set; }
    public string Material { get; set; }
    public decimal Cantidad { get; set; }
    public string UnidadDeMedida { get; set; }
    public int UnidadDeMedidaId { get; set; }
    public string Merma { get; set; }
    public bool Raiz { get; set; }
    public List<BilletesViewModel> ListaMateriales { get; set; }
    public List<SelectListItem> ListaUnidadesDeMedida { get; set; }
}
 

И это мое мнение. Я публикую все это на случай, если я упущу что-то еще.

 @model DulcesDeLaRosa.Models.BilletesViewModel

@{
    ViewBag.Title = "Nuevo Billete de Materiales";
    var disabled = Model.ListaMateriales != null amp;amp; Model.ListaMateriales.Count > 0 ? "disabled" : "";
}

@helper ShowTree(List<DulcesDeLaRosa.Models.BilletesViewModel> ListaMateriales, int nivel, int contador)
{
    if (ListaMateriales != null)
    {
        foreach (var material in ListaMateriales)
        {
            var marginLeft = 30 * nivel;
            var marginString = marginLeft   "px;";
            var claseBorde = nivel > 0 ? "" : "";
            <div class="form-inline col-12" style="margin-top:2%">
                @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                @Html.HiddenFor(model => material.Id)
                <hr />
                <div class="col-4 delarosa-max-width">
                    <div class="form-group col-12 delarosa-max-width" style="margin-left:@marginString">
                        @Html.EditorFor(model => material.Material, new { htmlAttributes = new { @class = "form-control delarosa-max-width" } })
                        @Html.ValidationMessageFor(model => material.Material, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="col-2">
                    <div class="form-group col-12 delarosa-max-width">
                        @Html.EditorFor(model => material.Cantidad, new { htmlAttributes = new { @class = "form-control delarosa-max-width" } })
                        @Html.ValidationMessageFor(model => material.Cantidad, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="col-2">
                    <div class="form-group col-12 delarosa-max-width">
                        @Html.DropDownListFor(model => material.UnidadDeMedidaId, material.ListaUnidadesDeMedida, new { @class = "form-control delarosa-max-width" })
                        @Html.ValidationMessageFor(model => material.UnidadDeMedidaId, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="col-2">
                    <div class="form-group col-12 delarosa-max-width">
                        @Html.EditorFor(model => material.Merma, new { htmlAttributes = new { @class = "form-control delarosa-max-width" } })
                        @Html.ValidationMessageFor(model => material.Merma, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="col-2">
                    <div class="form-group col-12">
                        <div class="col-9 offset-1">
                            <button type="submit" id="BtnAgregar" name="btn" class="btn btn-info delarosa-background" value="Agregar|@material.Id">Agregar Hijo</button>
                        </div>
                        <div class="col-2">
                            <button type="submit" id="BtnEliminar" name="btn" class="btn btn-info delarosa-background" value="Eliminar|@material.Id">X</button>
                        </div>
                    </div>
                </div>
            </div>
            if (material.ListaMateriales != null amp;amp; material.ListaMateriales.Any())
            {
                <ul>
                    @ShowTree(material.ListaMateriales, nivel   1, contador   1)
                </ul>
            }
            contador  ;
        }
    }
}

<div style="margin-top: 20px;">
    <h3>Nuevo Billete de Materiales</h3>
</div>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <div class="form-inline col-12 delarosa-margen-div delarosa-max-width">
        <div class="form-inline col-12 delarosa-max-width">
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            <div class="form-inline col-11">
                <div class="col-1">
                    <label class="delarosa-alineacion-izquierda">Familia: </label>
                </div>
                @Html.EditorFor(model => model.Familia, new { htmlAttributes = new { @class = "form-control", @id = "InputFamilia" } })
                @Html.ValidationMessageFor(model => model.Familia, "", new { @class = "text-danger" })
                @Html.HiddenFor(model => model.Raiz, new { @Value = Model.Raiz })
            </div>
            <div class="col-1">
                <input type="submit" id="BtnAgregarRaiz" name="btn" class="btn btn-info delarosa-background" value="Agregar Raiz" @disabled />
            </div>
        </div>
    </div>
    if (!Model.Raiz)
    {
        <div class="form-inline col-12 delarosa-margen-div">
            <div class="col-4">
                <div class="form-group col-12 delarosa-alineacion-centro">
                    <label class="delarosa-alineacion-centro">Material</label>
                </div>
            </div>
            <div class="col-2">
                <div class="form-group col-12 delarosa-alineacion-centro">
                    <label class="delarosa-alineacion-centro">Cantidad</label>
                </div>
            </div>
            <div class="col-2">
                <div class="form-group col-12 delarosa-alineacion-centro">
                    <label class="delarosa-alineacion-centro">Unidad</label>
                </div>
            </div>
            <div class="col-2">
                <div class="form-group col-12 delarosa-alineacion-centro">
                    <label class="delarosa-alineacion-centro">Merma %</label>
                </div>
            </div>
            <div class="col-2">
                <div class="form-group col-12 delarosa-alineacion-centro">
                    <label class="delarosa-alineacion-centro">Acciones</label>
                </div>
            </div>
        </div>
        <hr style="margin-bottom:2%" />
        @ShowTree(Model.ListaMateriales, 0, 0)
    }
    <div class="form-inline col-12 delarosa-margen-div" style="width:100%">
        <div class="col-6" style="text-align:left;">
            @Html.ActionLink("Regresar", "Index", null, new { @class = "btn btn-outline-danger" })
        </div>
        <div class="col-6" style="text-align:right;">
            <input type="submit" name="btn" value="Crear" class="btn btn-outline-danger" />
        </div>
    </div>
}
 

Кто-нибудь пробовал что-то подобное? Есть ли какой-нибудь способ, которым я могу это решить?

Я был бы признателен за любые указания

Комментарии:

1. Скорее, чем foreach (var material in ListaMateriales) тебе нужно for (var i=0;i<ListaMateriales.Count;i ) .EditorFor(model => ListaMateriales[i].Material,

2. @JeremyLakeman Да, это работает, если я зацикливаюсь на первом списке, но на самом деле я не знаю глубины списка, он может быть от 1 до n вложенных циклов.

3. Ах. ИМХО, создайте в Dictionary<string,BilletesViewModel> качестве своей модели, проиндексированную полем идентификатора. То, что вы отображаете значения в виде дерева, не означает, что вам нужно привязывать свою модель в виде дерева.

4. @JeremyLakeman Хорошо, да, я думаю, что в этом есть смысл. Я собираюсь попробовать этот подход. Спасибо.