penguin5000 Ответов: 2

Страница 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} - не данные страницы (из того, что я могу разобрать).

2 Ответов

Рейтинг:
11

penguin5000

Ответ был дан на другом форуме. Пожалуйста смотрите c# - ASP.NET Core 3.1 Razor pages - добавление различных дочерних объектов в заголовок - переполнение стека[^] относительно деталей.


Рейтинг:
0

Gerry Schmitz

Используйте иерархические представления; например

Передний край: вложенные сетки для иерархических данных | Microsoft Docs[^]


penguin5000

Спасибо. Это все еще будет применимо к страницам Razor?