Как правильно исправить проблему скаффолдинга MVVM с дубликатом имени тега?(ASP Core 2.2) - PullRequest
0 голосов
/ 06 февраля 2019

Вот моя проблема, у меня есть Book, который содержит List<Page>, который содержит List<Line>, и я пытаюсь создать представление, которое будет редактировать мою книгу.Этот вид содержит все строки из книги.Я сделал MVVM для List<Page>, который вызывает меньший MVVM для List<Line>.Проблема в том, что MVVM не считает все Line как одну отдельную форму, поэтому это происходит:

<form>
<h1>Page one</h1>
<input type="hidden" name="[0].lineContent" value=""/>
<input type="hidden" name="[1].lineContent" value=""/>
<h1>Page one</h1>
<input type="hidden" name="[0].lineContent" value=""/>
<input type="hidden" name="[1].lineContent" value=""/>
<input type="hidden" name="[2].lineContent" value=""/>
</form>

Каждый раз, когда цикл for для страницы повторяется, циклы my for в строках сбрасываются в 0, этосоздает повторяющиеся записи имени.

Существует несколько способов исправить это, самый простой:

  • Создание ввода вручную с уникальным идентификатором имени вместо использования помощников HTML

У меня следующий вопрос: как мне получить чистую бритву, которую можно использовать повторно и которая не будет дублировать записи имен в моей форме?

ОБНОВЛЕНИЕ:

Контекст:

Так же, как в книге приведены примеры, мои модели имеют одинаковую структуру.

в моем случае у меня есть представление, которое содержит список разделов, который содержит список подразделов, которыесодержит список SubmissionLine.

Вот мой основной вид:

        @model 
   QuotingPlus.Models.Submission

  @{
       ViewData["Title"] = "Edit";
   }

<form id="submission-form" asp-action="Edit">
     <div>
         <p class="d-inline-block">
             <a class="btn btn-primary" data-toggle="collapse" 
    href="#multiCollapseExample1" role="button" aria-expanded="false" aria-controls="multiCollapseExample1">Edit submission details</a>
        </p>
        <nav aria-label="breadcrumb" class="d-inline-block">
            <ol class="breadcrumb">
                <li class="breadcrumb-item">
                    <a href="/Clients/Details/@(Model.IdProjectNavigation.IdClientNavigation.IdClient)">@Model.IdProjectNavigation.IdClientNavigation.FirstName 
@Model.IdProjectNavigation.IdClientNavigation.LastName</a>
                </li>
                <li class="breadcrumb-item">
                    <a href="/Projects/Details/@(Model.IdProjectNavigation.IdProject)">@Model.IdProjectNavigation.Name</a>
                </li>
                <li class="breadcrumb-item active" aria-current="page">@Model.Number</li>
            </ol>
        </nav>
    </div>
    <div class="row">
        <div class="col mb-3">
            <div class="collapse multi-collapse" id="multiCollapseExample1">
                <div class="card card-body">
                    <h1>Submission details</h1>
                     <hr/>
                    <div class="row">
                        <div class="col-md-4">
                            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                            <input type="hidden" asp-for="IdSubmission"/>
                            <div class="form-group">
                                <label asp-for="IdTypeSubmission" class="control-label"></label>
                                <select asp-for="IdTypeSubmission" class="form-control" asp-items="ViewBag.IdTypeSubmission"></select>
                                <span asp-validation-for="IdTypeSubmission" class="text-danger"></span>
                            </div>
                            <div class="form-group">
                                <label asp-for="IdProject" class="control-label"></label>
                                <select asp-for="IdProject" class="form-control" asp-items="ViewBag.IdProject"></select>
                                <span asp-validation-for="IdProject" class="text-danger"></span>
                            </div>
                            <div class="form-group">
                                <label asp-for="Number" class="control-label"></label>
                                <input asp-for="Number" class="form-control"/>
                                <span asp-validation-for="Number" class="text-danger"></span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div id="save-warning" style="display: none;" class="alert alert-info alert-dismissible fade show" role="alert">
        <strong>WARNING!</strong> Make sure you save before leaving.
        <button type="button" class="close" data-dismiss="alert" aria-label="Close" onclick="SetWarningDisplayPreferenceCookie();">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>
    <div id="carouselIndicators" style="height: 100% !important;" class="carousel slide pb-5 mb-5" data-interval="false">
        <div class="carousel-inner">
            @{
            Html.RenderPartial("SubmissionSectionEditor",  Model.SubmissionSection.ToList());
            }
        </div>
        <nav class="navbar navbar-light bg-secondary mb-0 pt-2 fixed-bottom">
            <div>
                <button type="submit" value="Save" class="btn btn-default text-white">
                    <i class="material-icons" style="font-size: 2em;">
                        save
                    </i>
                </button>
            </div>

            <a class="col text-center mh-100 pt-2 pb-2" href="#carouselIndicators" role="button" data-slide="prev">
                <span class="carousel-control-prev-icon" aria-hidden="false"></span>
            </a>
            <a class="col text-center mh-100 pt-2" href="#carouselIndicators" role="button" data-slide="next">
                 <span class="carousel-control-next-icon" aria-hidden="false"></span>
            </a>

            <div>
                <a asp-action="Index" class="btn text-white">
                    <i class="material-icons" style="font-size: 2em;">
                        cancel
                    </i>
                </a>
            </div>
        </nav>
    </div>
</form>

Вот SubmissionSectionEditor.cshtml

@model List<SubmissionSection>

@{
    var isFirstCarouselItem = true;
}

@for (var indexSection = 0; indexSection < Model.Count(); indexSection++)
{
    <div class="carousel-item @((isFirstCarouselItem) ? "active" : "")">
        @{
            isFirstCarouselItem = false;
        }

    <h1>@Model[indexSection].IdSectionNavigation.Name</h1>
        <div id="@(Model[indexSection].IdSection + "accordion")">


            @{
                var submissionSubSections = M odel[indexSection].SubmissionSubSection;
            }

            @if (submissionSubSections != null)
            {
                Html.RenderPartial("SubmissionSubSectionEditor", submissionSubSections.ToList());
            }

        </div>
    </div>
}

Вот SubmissionSubSectionEditor.cshtml

@model List<SubmissionSubSection>

@for (var indexSubSection = 0; indexSubSection <  Model.Count; indexSubSection++)
{
    <div class="card">
        <div class="card-header" id="@(Model[indexSubSection].IdSubSection + "SubSectionHeader")">
            <h2 class="mb-0">
                <button type="button" class="btn btn-link collapsed" data-toggle="collapse" data-target="@("#" + Model[indexSubSection].IdSubSection + "SubSectionCollapse")" aria- 
   expanded="true" aria-controls="@(Model[indexSubSection].IdSubSection + "SubSectionCollapse")">

    @Model[indexSubSection].IdSubSectionNavigation.Name
                </button>
             </h2>
         </div>
         <div id="@(Model[indexSubSection].IdSubSection + "SubSectionCollapse")" class="collapse" aria-labelledby="@(Model[indexSubSection].IdSubSection + 
"SubSectionHeader")" data-parent="@("#" + Model[indexSubSection].IdSubmissionSectionNavigation.IdSection + "accordion")">
            <div class="card-body">
                <table class="table w-100">
                    <thead class="thead-dark">
                    <tr>
                        <th>Quantity</th>
                        <th>Article</th>
                         <th>Total Material</th>
                        <th>Unit Price Material</th>
                        <th>Total Sub Contractor</th>
                        <th>Unit Price Sub Contractor</th>
                        <th>Total Workforce</th>
                        <th>Unit Price Workforce</th>
                        <th>Display</th>
                    </tr>
                    </thead>
                    <tbody>
                    @{
                        Html.RenderPartial("SubmissionLineEditor", Model[indexSubSection].SubmissionLine.ToList());
                    }
                    </tbody>
                </table>
            </div>
        </div>
    </div>
}

Вот SubmissionLineEditor.cshtml

@model List<SubmissionLine>

@for (var indexLine = 0; indexLine < Model.Count; indexLine++)
{
    <tr>
        @Html.HiddenFor(x => Model[indexLine].IdSubmissionLine)
        @Html.HiddenFor(x => Model[indexLine].IdArticle)
        @Html.HiddenFor(x => Model[indexLine].IdSubmissionSubSection)
        <td>@Html.TextBoxFor(x => Model[indexLine].Quantity, new {@type = "number", @step = "0.5", @min="0"})</td> 
<td>@Model[indexLine].IdArticleNavigation.Designation</td>
        <td>@Model[indexLine].TotalMaterial</td>

<td>@Model[indexLine].IdArticleNavigation.UnitPriceMaterial</td>
        <td>@Model[indexLine].TotalSubContractor</td>

<td>@Model[indexLine].IdArticleNavigation.UnitPriceSubContractor</td>
        <td>@Model[indexLine].TotalWorkforce</td>

<td>@Model[indexLine].IdArticleNavigation.UnitPriceWorkforce</td>
        <td>@Html.CheckBoxFor(x => Model[indexLine].IsDisplayed, new {@class = "checkbox"}). 
</td>
    </tr>
}

Я только хочу знать , как я могу сохранить эту структуру с помощью MVVM и избежать проблемы с дублированием входного имени ?

ОБНОВЛЕНИЕ:

Я не совсем уверен, почему это было бы полезно, так как я получаю ввод дубликатов имен, но вот мое действие сохранения:

[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin, SuperAdmin, Employe")]
public ActionResult Edit(int id, Submission submission, [FromForm] List<SubmissionLine> lines)
    {
        var test = Request.Form;

        if (id != submission.IdSubmission)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            SubmissionUpdateHelper.SaveSubmissionModifications(_context, submission, lines);

            return RedirectToAction(nameof(Index));
        }

        ViewData["IdProject"] = new SelectList(_context.Project, "IdProject", "Name", submission.IdProject);
        ViewData["IdTypeSubmission"] = new SelectList(_context.TypeSubmission, "IdTypeSubmission",
            "TypeSubmission1", submission.IdTypeSubmission);
        return View(submission);
    }

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Наконец, я только что добавил ввод вручную, чтобы сохранить шаблон MVVM.Я также использовал переменную приращения в TempData, чтобы я мог отслеживать ввод

в Edit.cshtml

@{
    TempData["submissionLineCount"] = 0;
}

вот новая версия SubmissionLineEditor.cshtml

@model List<SubmissionLine>

@for (var indexLine = 0; indexLine < Model.Count; indexLine++)
{
    <tr>
        <input name="[@(TempData["submissionLineCount"])].IdSubmissionLine" value="@(Model[indexLine].IdSubmissionLine)" type="hidden"/>
        <input name="[@(TempData["submissionLineCount"])].IdArticle" value="@(Model[indexLine].IdArticle)" type="hidden"/>
        <input name="[@(TempData["submissionLineCount"])].IdSubmissionSubSection" value="@(Model[indexLine].IdSubmissionSubSection)" type="hidden"/>
        <td>@TempData["submissionLineCount"]</td>
        <td>
            <input name="[@(TempData["submissionLineCount"])].Quantity" value="@(Model[indexLine].Quantity)" type="number" step="0.5" min="0"/>
        </td>
        <td>@Model[indexLine].IdArticleNavigation.Designation</td>
        <td>@Model[indexLine].TotalMaterial</td>
        <td>@Model[indexLine].IdArticleNavigation.UnitPriceMaterial</td>
        <td>@Model[indexLine].TotalSubContractor</td>
        <td>@Model[indexLine].IdArticleNavigation.UnitPriceSubContractor</td>
        <td>@Model[indexLine].TotalWorkforce</td>
        <td>@Model[indexLine].IdArticleNavigation.UnitPriceWorkforce</td>
        <td>
            <input type="checkbox" name="[@(TempData["submissionLineCount"])].IsDisplayed" class="checkbox" value="@(Model[indexLine].IsDisplayed)"/>
        </td>
    </tr>
    {
        TempData["submissionLineCount"] = (Convert.ToInt32(TempData["submissionLineCount"]) + 1);
    }
}

Это явно не лучший способ, я надеюсь, что в будущем будет больше документации о том, как применять MVVM в AspNet.Core ...

Если этот ответ устарел, обязательно напишитесвой собственный!

0 голосов
/ 12 февраля 2019

Для отображения свойств подсписка в представлении, попробуйте код ниже:

<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Id" />
            <div class="form-group">
                <label asp-for="BookName" class="control-label"></label>
                <input asp-for="BookName" class="form-control" />
                <span asp-validation-for="BookName" class="text-danger"></span>
            </div>
            <div class="form-group">
                @for (int i = 0; i < Model.Pages.Count; i++)
                {
                    <div class="form-group">
                        <label asp-for="Pages[i].PageName" class="control-label"></label>
                        <input asp-for="Pages[i].PageName" class="form-control" />
                        <span asp-validation-for="Pages[i].PageName" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        @for (int j = 0; j < Model.Pages[i].Lines.Count; j++)
                        {
                            <div class="form-group">
                                <label asp-for="Pages[i].Lines[j].LineContent" class="control-label"></label>
                                <input asp-for="Pages[i].Lines[j].LineContent" class="form-control" />
                                <span asp-validation-for="Pages[i].Lines[j].LineContent" class="text-danger"></span>
                            </div>
                        }
                    </div>

                }
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
...