首页 > 解决方案 > 在 .NET MVC 应用程序中处理来自动态子表单的数据输入的最佳方法

问题描述

我对 .NET MVC 比较陌生,并且一直在努力使用我正在开发的 Web 应用程序。总而言之,这个应用程序由一个表单组成,主要部分是输入客户的姓名,然后是一个添加孩子的按钮。单击此按钮时,将通过局部视图显示一个子表单。当单击子表单上的保存按钮时,我不确定如何处理数据(但子表单将折叠,HTML 端的手风琴样式),但要点是客户可以添加一个或许多子表单输入他们孩子的名字和年龄。

处理这些表单上的输入的最佳方法是什么?我和一些同事交谈过,他们似乎不确定。有人建议我首先将“父”表单保存到数据库,然后在每个子表单(子表单)中,当单击保存按钮时,将它们也发送到数据库,使用父 ID 连接它们。其他人建议为此使用 Vue。在模型绑定或将数据发送回控制器方面,您有什么建议?

首先,表单的视图模型如下所示:

namespace ModelBindingObjects.ViewModel
{
    public class ParentVM
    {
        public string Name { get; set; }

        public List<ChildVM> Children { get; set; }
    }

public class ChildVM
    {
        public string Name { get; set; }

        public int Age { get; set; }
    }

}

对于 db 端,模型如下所示:

    public partial class Parent
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }

        [Required]
        [StringLength(50)]
        public string Name { get; set; }
    }

 public partial class Child
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }

        public int ParentId { get; set; }

        [Required]
        [StringLength(50)]
        public string Name { get; set; }

        public int Age { get; set; }

视图看起来像这样

@model ModelBindingObjects.ViewModel.ParentVM
<h3>A Sample Form</h3>
@using (Html.BeginForm())
{
    <div class="container">
        <div class="row">
            <div class="form-row">
                <div class="form-group col-md-6">
                    @Html.LabelFor(x => x.Name, new { @class = "required" })
                    @Html.TextBoxFor(x => x.Name, new { @class = "form-control" })
                </div>
                <div class="col-md-6">

                </div>
            </div>
        </div>
        <div class="row">
            <div class="form-group col-md-6">
                <div class="addChildren">
                    <h5 class="topspacing-med btmspacing-med">Your Child(ren) Details</h5>
                    <div class="displayChildForm">
                        @*@Html.Partial("_AddChild", new ViewDataDictionary()
                            {
                                TemplateInfo = new TemplateInfo()
                                { HtmlFieldPrefix = "Test" }
                            })*@
                    </div>
                    <button type="button" class="btn btn-outline-secondary btn-sm btn-block btmspacing-med" id="addChild">Add New Child</button>
                </div>
            </div>
            <div class="form-group col-md-6"></div>
        </div>
    </div>
}


@section scripts {
    <script type="text/javascript">

       var hideButtons = function () {
            $("#addChild").hide();
        };

        $("#saveChild").click(function () {
            console.log("testing");
            $(".panel-body").hide();
        });

        $("#addChild").click(function () {
            $.ajax({
                url: '@Url.Action("RenderAddChildForm", "Home")',
                dataType: "html",
                type: 'GET',
                success: function (result) {
                    $('.displayChildForm').append(result);
                    hideButtons();
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    console.log(xhr.status);
                    console.log(thrownError);
                },

            });
        });


    </script>

然后局部视图...

@model ModelBindingObjects.ViewModel.ChildVM

    <div class="panel panel-primary">
        <div class="panel-heading"><h5>Add A Child</h5></div>
        <div class="panel-body">
            <div class="form-group row">
                <div class="col-md-12">
                    <input type="hidden" name="products.Index" value="test" />
                    @*@Html.LabelFor(x => x.Name)
                    @Html.TextBoxFor(x => x.Name, new { @class = "form-control" })*@
                    <input type="text" name="[test].Name" value="Delaney" />
                </div>
            </div>
            <div class="form-group row">
                <div class="col-md-12">
                    <input type="text" name="[test].Age" value="12" />
                </div>
            </div>
            <div class="btn-group float-right mt-2" role="group">
                <button class="btn btn-primary btn-sm btn-block" type="submit" id="saveChild">Save</button>
            </div>
        </div>
    </div>

最后,好的旧控制器:

namespace ModelBindingObjects.Controllers
{
    public class HomeController : Controller
    {
        private string PartialViewPath(string name)
        {
            return $"~/Views/Partials/{name}.cshtml";
        }

        // GET: Home
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult RenderAddChildForm()
        {
            return PartialView(PartialViewPath("_AddChild"));
        }
    }



}

标签: c#asp.netasp.net-mvcrazormodel-binding

解决方案


这取决于页面流程的复杂程度、您对 Vue 的熟悉程度以及是否有单独的编辑页面或者您希望支持在同一页面内进行编辑/删除。如果它所做的只是拯救孩子,那么您可以使用 AJAX 请求轻松做到这一点,而无需引入 Vue。

一种方法是将这两个操作分开,这样用户就不能添加孩子,除非他们已经添加并保存了父母的数据。在父表单保存成功时,返回保存的 parentId,并禁用按钮。对于每个子表单,当用户点击“保存孩子”时,发送 {parentId, childVm}。

另一种方法是整个页面只有一个保存按钮,即每个孩子没有自己的保存按钮。displayChildFormdiv 充当具有单个“添加子”按钮的输入集合,该按钮创建更多子部分视图并将它们附加到自身。当用户单击页面的保存按钮时,您发送 {parentVm, childVmCollection[]}。

displayChildForm您可以混合使用这两种方法,因此您最终会在div 中得到一个“保存父级”按钮和一个“保存/编辑子级”按钮。单击保存子按钮时,您发送 {parentId, childVmCollection[]}。


推荐阅读