Страница Razor добавление элементов в список и обновление частичных представлений - не MVC
Я новичок в разработке веб-приложений, и мне интересно, может ли кто-нибудь указать мне правильное направление с помощью этого? Мне кажется, я знаю, в чем проблема, но не знаю, как ее решить.
То, что у меня есть, - это сложная модель, где заголовок может содержать дочерний элемент, и каждый дочерний элемент может сам иметь своих собственных детей (разных типов).
Мой демонстрационный код, показанный здесь, имеет заголовок и два списка. Если я нажимаю кнопку, чтобы добавить дочерний элемент в первый или второй список, то первоначальная проблема заключается в том, что элементы не отображаются. Другая проблема заключается в том, что я, похоже, не могу продолжать добавлять элементы в любой список.
Чтобы попытаться увидеть, что происходит, я добавил раздел, чтобы показать innerHTML, чтобы увидеть, что такое данные - и это иллюстрирует, что если я нажимаю, чтобы добавить в первый список, некоторые данные появляются для первого списка, но если я нажимаю, чтобы добавить во второй список, новые данные исчезают из первого списка, в то время как новый элемент появляется, как и ожидалось, во втором списке.
Я думаю, что проблема заключается в том, что модель не обновляется, чтобы отразить новые элементы, но я понимаю, что мы все равно не сможем сделать это с помощью Javascript. Итак, я думаю, что мне нужно разделить все мои частичные представления, поэтому у меня есть основное частичное представление, содержащее много частичных представлений, и когда мой вызов Ajax будет успешным, обновите основное частичное представление.
Мой PageModel
namespace ParentChildDemo.Pages { public class IndexModel : PageModel { private readonly ILogger<IndexModel> _logger; [BindProperty] public Header MyHeader { get; set; } = new Header(); public IndexModel(ILogger<IndexModel> logger) { _logger = logger; } public void OnGet() { MyHeader.Id = 1; MyHeader.MyHeaderProperty = "HeaderTest1"; MyHeader.ChildOfHeader.Add(new ChildOfHeader()); for (int i = 1; i <= 3; i++) { var childOfChild = new ChildOfChild() { Id = i, HeaderId = MyHeader.Id, MyChildProperty = $"FirstChildTest{i}" }; MyHeader.ChildOfHeader[0].MyFirstChildList.Add(childOfChild); } for (int i = 1; i <= 2; i++) { var childOfChild = new ChildOfChild() { Id = i, HeaderId = MyHeader.Id, MyChildProperty = $"SecondChildTest{i}" }; MyHeader.ChildOfHeader[0].MySecondChildList.Add(childOfChild); } } public PartialViewResult OnPostAddNewFirstListChildItem([FromBody] Header myHeader) { if (myHeader.ChildOfHeader[0].MyFirstChildList == null) myHeader.ChildOfHeader[0].MyFirstChildList = new List<ChildOfChild>(); var childId = myHeader.ChildOfHeader[0].MyFirstChildList.Count + 1; myHeader.ChildOfHeader[0].MyFirstChildList.Add(new ChildOfChild { Id = childId, HeaderId = myHeader.Id, MyChildProperty = $"FirstChildTest{childId}" }); var partialView = "_ListPartialView"; //var partialView = "_FirstListItemPartial"; var data = new IndexModel(_logger); data.MyHeader = myHeader; var myViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { { partialView, myHeader } }; //var myViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { { partialView, myHeader.ChildOfHeader[0].MyFirstChildList } }; myViewData.Model = data; var partialViewResult = new PartialViewResult() { ViewName = partialView, ViewData = myViewData, }; return partialViewResult; } public PartialViewResult OnPostAddNewSecondListChildItem([FromBody] Header myHeader) { if (myHeader.ChildOfHeader[0].MySecondChildList == null) myHeader.ChildOfHeader[0].MySecondChildList = new List<ChildOfChild>(); var childId = myHeader.ChildOfHeader[0].MySecondChildList.Count + 1; myHeader.ChildOfHeader[0].MySecondChildList.Add(new ChildOfChild { Id = childId, HeaderId = myHeader.Id, MyChildProperty = $"SecondChildTest{childId}" }); var partialView = "_ListPartialView"; //var partialView = "_SecondListItemPartial"; var data = new IndexModel(_logger); data.MyHeader = myHeader; var myViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { { partialView, myHeader } }; //var myViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { { partialView, myHeader.ChildOfHeader[0].MySecondChildList } }; myViewData.Model = data; var partialViewResult = new PartialViewResult() { ViewName = partialView, ViewData = myViewData, }; return partialViewResult; } } public class Header { public int Id { get; set; } public string MyHeaderProperty { get; set; } public List<ChildOfHeader> ChildOfHeader { get; set; } = new List<ChildOfHeader>(); } public class ChildOfHeader { public List<ChildOfChild> MyFirstChildList { get; set; } = new List<ChildOfChild>(); public List<ChildOfChild> MySecondChildList { get; set; } = new List<ChildOfChild>(); } public class ChildOfChild { public int Id { get; set; } public int HeaderId { get; set; } public string MyChildProperty { get; set; } } }
Мою страницу индекса
@page @model IndexModel @{ ViewData["Title"] = "Home page"; } <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p> </div> <div> <a class="btn btn-sm btn-info text-white" onclick="AddListItem(1)">Add Child to First list</a> <a class="btn btn-sm btn-info text-white" onclick="AddListItem(2)">Add Child to Second list</a> </div> <br /> <div> <div>MyHeaderProperty value: @Model.MyHeader.MyHeaderProperty</div> <br /> <div class="container"> <div class="row"> <div class="col-6 font-weight-bold">First List</div> <div class="col-6 font-weight-bold">Second List</div> </div> <div class="ListPartialView"> <partial name="_ListPartialView" model="@Model" /> </div> </div> <br /> <div class="bg-warning" id="HtmlContent"></div> @Html.AntiForgeryToken() </div> <script type="text/javascript"> function AddListItem(listNumber) { var model = @Json.Serialize(Model.MyHeader); var handler; var partialView; if (listNumber == 1) { handler = "?handler=AddNewFirstListChildItem"; partialView = "#ListPartialView";//"#FirstListPartial"; } else { handler = "?handler=AddNewSecondListChildItem"; partialView = "#ListPartialView";//"#SecondListPartial"; } $.ajax({ type: "POST", url: handler, data: JSON.stringify(model), dataType: "html", contentType: "application/json", headers: { RequestVerificationToken: $('input:hidden[name="__RequestVerificationToken"]').val() }, success: function (result) { document.getElementById("HtmlContent").innerHTML = result.toString(); $(partialView).html(result); }, failure: function (result) { alert("Failed"); } }); } </script>
Мой основной частичный вид (_ListPartialView)
@model IndexModel @for (int i = 0; i < Model.MyHeader.ChildOfHeader.Count; i++) { ViewData["ChildIndex"] = i; <div class="row"> <div id="FirstListPartial" class="col-6"> <partial name="_FirstListItemPartial" model="@Model" view-data="ViewData" /> </div> <div id="SecondListPartial" class="col-6"> <partial name="_SecondListItemPartial" model="@Model" view-data="ViewData" /> </div> </div> }
Мой первый список частичным видом (_FirstListItemPartial)
@model IndexModel @{ var indexId = (int)ViewData["ChildIndex"]; } <table> @foreach (var myChildItem in Model.MyHeader.ChildOfHeader[indexId].MyFirstChildList) { <tr> <td>@myChildItem.Id</td> <td>@myChildItem.MyChildProperty</td> </tr> } </table>
Мой второй список частичное представление (_SecondListItemPartial)
@model IndexModel @{ var indexId = (int)ViewData["ChildIndex"]; } <table> @foreach (var myChildItem in Model.MyHeader.ChildOfHeader[indexId].MySecondChildList) { <tr> <td>@myChildItem.Id</td> <td>@myChildItem.MyChildProperty</td> </tr> } </table>
Что я уже пробовал:
В моем "скрипте" я думаю, что мне нужно ссылаться на мою страницу, а не на мою модель каждый раз, когда нажимается одна из кнопок. Я попытался сериализовать свое частичное представление (ListPartialView), и я изменил свой тип параметра на "динамический" и удалил [FromBody], но мое содержимое объекта всегда {object} - не данные страницы (из того, что я могу разобрать).