Лучший подход к работе с входными данными из динамических подформ в приложении .NET MVC - PullRequest
0 голосов
/ 02 июля 2019

Я относительно новичок в .NET MVC и боролся с веб-приложением, над которым я работаю.В общем, это приложение состоит из формы, основной части, которая вводит имя клиента, а затем есть кнопка для добавления дочернего элемента.Когда эта кнопка нажата, субчасть появляется через частичное представление.Я еще не уверен, что делать с данными, когда нажата кнопка «Сохранить» в подформе (но форма перевернется, стиль аккордеона на стороне HTML), но суть в том, что клиент может добавить один илимногие дочерние формы для ввода имен и возрастов своих детей (детей).

Каков наилучший способ обработки входных данных в этих формах?Я говорил с некоторыми коллегами, и они казались неуверенными.Один из них предложил мне сначала сохранить «родительскую» форму в базе данных, а затем внутри каждой подформы (дочерней), когда нажата кнопка «Сохранить», также отправить их в базу данных, используя родительский идентификатор для их соединения.Кто-то еще предложил использовать 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; }
    }

}

Для стороны базы данных,модели выглядят так:

    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"));
        }
    }



}

Ответы [ 2 ]

0 голосов
/ 04 июля 2019

Вы можете просто привязать модель к свойству ICollection в модели

https://docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-2.2#collections

старичок, но голди: https://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

Вы также можете найти мои библиотеки полезными для такого рода вещей.

https://github.com/mcintyre321/FormFactory https://github.com/mcintyre321/AspNetCoreJTokenModelBinder

0 голосов
/ 04 июля 2019

Это зависит от сложности потока страниц, от того, насколько вы знакомы с Vue, и от того, есть ли отдельная страница редактирования или вы хотите поддерживать редактирование / удаление на той же странице.Если все, что он делает - это сохраняет дочерние элементы, то вы можете легко сделать это с помощью запросов AJAX, не представляя Vue.

Один из подходов состоит в том, чтобы разделить две операции, поэтому пользователь не может добавить дочерний элемент, если он не добавил исохранил данные родителя.При успешном сохранении родительской формы верните сохраненный parentId и отключите кнопку.Для каждой подчиненной формы, когда пользователь нажимает «сохранить дочерний элемент», отправьте {parentId, childVm}.

Другой подход состоит в том, чтобы иметь только одну кнопку сохранения для всей страницы, т.е. каждый дочерний элемент не получает свою собственную кнопку сохранения.,displayChildForm div действует как набор входных данных с помощью единственной кнопки «добавить дочерний элемент», которая создает дополнительные дочерние частичные представления и добавляет их к себе.Когда пользователь нажимает кнопку сохранения страницы, вы отправляете {parentVm, childVmCollection []}.

Вы можете смешать оба подхода, так что в итоге вы получите кнопку «сохранить родителя» и одну кнопку «сохранить / редактировать детей» в displayChildForm div.Нажав кнопку «Сохранить дочерние элементы», вы отправляете {parentId, childVmCollection []}.

...