首页 > 解决方案 > 在 ASP.NET MVC 中使用一种形式创建模型的多个实例

问题描述

我正在构建一个表单,该表单创建一个具有不同模型列表作为属性的模型。这是模型:

public class JobViewModel
    {
        [Required]
        public string JobName { get; set; }
        [Required]
        public string JobTotal { get; set; }
        public bool Recurring { get; set; }
        public List<ServiceViewModel> ExtraServices { get; set; }
        
    }

这是 ServiceViewModel 类:

public class ServiceViewModel
    {
        public string ServiceName { get; set; }
        public string ServiceTotal { get; set; }
    }

任何单个 JobViewModel 都可以有 0-4 个与之关联的额外服务,因此在表单中,用户可以根据需要添加和删除额外的服务字段。这是创建 JobViewModel 的表单,以及一些允许用户添加和删除额外服务字段的 jQuery:(编辑:这是 _AddJobPartial 部分视图)

@{
    //create unique id's so the ajax toggle and delete scripts only affect one widget.
    var addJobWidgetId = "add-job-widget" + Model.JobId;
    var addServiceWidgetId = "add-service-widget" + Model.JobId;
    var addServiceButtonId = "add-service-button" + Model.JobId;
    var widgetTitleId = "widget-title" + Model.JobId;
    var deleteButtonId = "delete-button" + Model.JobId;
    var widgetId = "widget-" + Model.JobId;
}
<div class="row" id="@widgetId">
    <div class="border border-dark p-1 m-3">
        <div id="job-header" class="d-flex justify-content-between">

            <div>
                <label class="widget-title-text" id="@widgetTitleId" for="job-name">Job:</label>
                <input type="text" id="job-name" />
            </div>
            <div>
                <button class="btn btn-danger btn-sm deleteButton" id="@deleteButtonId">X</button>
            </div>

        </div>

        <div id="@addJobWidgetId" class="add-job-widget border border-dark">
          
            <div class="form-group">
                <label for="total-cost-input">Job Total</label>
                <input type="text" id="total-cost-input" />
            </div>
            <div class="form-group">
                <input type="checkbox" value="recurring" id="recurring_box" name="recurring_box"/>
                <label for="recurring_box">Is this job recurring?</label>
            </div>

            <div class="p-1 extra-service-widget">
                <button class="btn btn-info btn-sm" id="@addServiceButtonId">
                    Add extra service
                </button>
                <!--EXTRA SERVICE-->
                <div id="@addServiceWidgetId">
                    
                </div>
                <!---->
            </div>
        </div>
    </div>

</div>


<script>
    var servicesAdded = 0;

    $("#" + "@addServiceButtonId").click(function (e) {
        e.preventDefault();
        servicesAdded++;
        $.ajax({
            type: "GET",
            url: "/Daysheet/GetExtraServicePartial/" + servicesAdded.toString(),
            headers: {
                "RequestVerificationToken": requestVerificationToken
            }
        }).done(function (data, statusText, xhdr) {
            console.log("Done");
            $("#" + "@addServiceWidgetId").append(data);
        }).fail(function (xhdr, statusText, errorText) {
            console.log("Failed");
            $("#" + "@addServiceWidgetId").text(JSON.stringify(xhdr));
        });
        
    });

</script>

这是单击上述表单上的“添加额外服务”按钮时创建的部分视图:

@{
    var extraServiceListId = "extra-service-list" + Model.ServiceId;
    var extraServiceWidgetId = "extra-service-widget" + Model.ServiceId;
    var serviceTotalId = "service-total" + Model.ServiceId;
    var deleteServiceId = "delete-service" + Model.ServiceId;
}
<div class="p-1 border border-dark" id="@extraServiceWidgetId">
    <select id="@extraServiceListId">
        <option>Extra services...</option>
        <option value="purewater">Pure water</option>
        <option value="powerwashing">Power washing</option>
        <option value="roofwashing">Roof washing</option>
        <option value="awningclean">Awning clean</option>
    </select>
    <input type="text" id="@serviceTotalId" placeholder="Service total" />
    <button class="btn btn-danger btn-sm deleteButton float-right" id="@deleteServiceId">X</button>
</div>

<script>
    $(document).on('click', '#' + '@deleteServiceId', function (e) {
        e.preventDefault();
        const elementToRemove = document.getElementById("@extraServiceWidgetId");
        jQuery(elementToRemove).slideToggle().fadeOut('slow', function () {
            elementToRemove.remove();
        });
    });
</script>

我想知道如何在提交作业表单时为每个额外的服务小部件创建一个 ServiceViewModel,并将它们附加到 JobViewModel 上的 ExtraServices 属性中。

我在这里找到了一些非常接近我需要的东西,但我不确定这个解决方案如何处理添加然后删除字段的用户,这会导致索引错误。该链接提到他们的解决方案能够解决该问题,但我不明白发生了什么。

编辑:

这是带有表单元素的实际视图。此视图有一个按钮,用于添加我在上面发布的 _AddJobPartial 部分视图。

这是 GetCommission.cshtml,它由我在下面发布的控制器操作之一返回。

@{
    ViewData["Title"] = "Get Commission";
    Layout = "~/Views/Shared/_DaysheetSubLayout.cshtml";
}
@model GetCommissionsViewModel

<form method="post">
    <div class="row">
        <div class="col-md-5 offset-1">
            <div id="jobs-div" class="flex-fill p-2">
            </div>
        </div>
        <div class="col-md-3 offset-1 d-flex align-items-center justify-content-center submit-jobs-wrapper">
            <input class="btn btn-outline-primary w-100 h-100 submit-jobs-button"
                   type="submit"
                   value="Submit" />
        </div>
    </div>
</form>

<input type="button" id="add-job-button" value="Add a Job" data-url="@Url.Action("GetAddJobsPartial", "Daysheet")" />


@section scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}

    <script type="text/javascript">let requestVerificationToken = $("input[name='__RequestVerificationToken']").val();
        var numClicked = 0;
        $("#add-job-button").click(function () {
            console.log("Controller Button clicked");
            console.log($("#add-job-button").data("url"));
            numClicked++;
            console.log(numClicked);
            $.ajax({
                type: "GET",
                url: "/Daysheet/GetAddJobsPartial/" + numClicked.toString(),
                headers: {
                    "RequestVerificationToken": requestVerificationToken
                }
            }).done(function (data, statusText, xhdr) {
                console.log("Done");
                $("#jobs-div").append(data);
            }).fail(function (xhdr, statusText, errorText) {
                console.log("Failed");
                $("#jobs-div").text(JSON.stringify(xhdr));
            });
        });</script>


}

这是我的控制器类中的相关操作:

[HttpPost]
        public IActionResult GetCommission(CrewDaysheetsListViewModel crewDaysheetsListViewModel)
        {
            var getCommissionsViewModel = new GetCommissionsViewModel { DaysheetIds = crewDaysheetsListViewModel.CommissionsViewDaysheetIds };
            return View(getCommissionsViewModel);
        }

        public IActionResult GetAddJobsPartial(string Id)
        {
            var addJobPartialViewModel = new AddJobPartialViewModel { JobId = Id};
            return PartialView("_AddJobsPartial", addJobPartialViewModel);
        }

        
        public IActionResult GetExtraServicePartial(string Id)
        {
            var extraServicePartialViewModel = new ExtraServicePartialViewModel { ServiceId = Id };
            return PartialView("_ExtraServicePartialView", extraServicePartialViewModel);
        }

我用于这些页面的视图模型非常简单:

public class GetCommissionsViewModel
    {
        public List<string> DaysheetIds { get; set; }
    }

public class AddJobPartialViewModel
    {
        public string JobId { get; set; }
    
    }
public class ExtraServicePartialViewModel
    {
        public string ServiceId { get; set; }
    }

我将 JobId 和 serviceId(可能可以将它们组合成一个 ViewModel)与局部视图一起使用,为它们的元素提供唯一的 id,因此删除按钮会删除正确的局部视图等。这个数字会在每次按下按钮时迭代_AddJobPartial 和 _ExtraServicePartial 的底部。

标签: asp.net-mvcformsasp.net-core

解决方案


推荐阅读