Click here to Skip to main content
15,882,017 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm new to web app development, and I wonder if somebody could point me in the right direction with this? I think I know what the problem is, but I don't know how to fix it.

What I have is a complex model where a header can contain a child, and each child can itself have its own children (of different types).

My demo code shown here has a header, and two lists. If I click the button to add a child item to either the first list or a second list, the initial problem I have is that the items don't appear. The other problem is that I don't appear to be able to keep on adding items to either list.

To try to see what is going on, I added a section to show the innerHTML to see what the data is - and this illustrates that if I click to add to the first list, some data appears for the first list, but if I click to add to the second list, the new data disappears from the first list whilst the new item appears as expected in the second list.

I think the problem is that the Model isn't updated to reflect the new items - but I understand that we shouldn't be able to do that with Javascript anyway. So, I think I need to separate all my partial views, so I have a main partial view containing lots of partial views, and when my Ajax call is successful, refresh the MAIN partial view.

My 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; }
    }
}


My Index page

@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>


My Main partial view (_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>
}


My My first list partial view (_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>


My second list partial view (_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>


What I have tried:

In my < script > I think I need to refer to my page, and not my Model every time one of the buttons is pressed. I have tried to serialize my partial view (ListPartialView), and I have changed my parameter type to 'dynamic' and removed the [FromBody], but my object content is is always {object} - not the page data (from what I can make out).
Posted
Updated 14-Oct-20 23:49pm

The answer was provided on another forum. Please see c# - ASP.NET Core 3.1 Razor pages - adding different child objects to header - Stack Overflow[^] for details.
 
Share this answer
 
 
Share this answer
 
Comments
penguin5000 13-Oct-20 14:07pm    
Thanks. Is this still going to be applicable to Razor pages?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900