1

I'm new to this and I've been struggling with this for days!

What I want to do is simply add a child item to a parent, and refresh the partial view. My problem is when the code drops into the OnGetAddNewChildItem method, the bound property on the PageModel class is empty (it isn't null, it just has no data in it) so I can't add an child to this. To try and work around this, I'm trying to pass data INTO the method, but this IS null.

Strangely, in the actual solution I'm working on, I can't even get it to drop into the PageModel class UNLESS it is a PUT or a POST - but if I can get this demo working, I'm sure I'll be able to get the main solution working.

My PageModel class

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.MyChildPropertiesList.AddRange(
                new List<Child> {
                    new Child() { Id = 1, HeaderId = MyHeader.Id, MyChildProperty = "ChildTest1" },
                    new Child() { Id = 2, HeaderId = MyHeader.Id, MyChildProperty = "ChildTest2" },
                    new Child() { Id = 3, HeaderId = MyHeader.Id, MyChildProperty = "ChildTest3" }
                });
        }

        public PartialViewResult OnGetAddNewChildItem([FromBody] Header myHeader)
        {
            if (myHeader.MyChildPropertiesList == null)
                myHeader.MyChildPropertiesList = new List<Child>();

            myHeader.MyChildPropertiesList.Add(new Child
            {
                Id = 4,
                HeaderId = myHeader.Id,
                MyChildProperty = "ChildTest4"
            });

            var partialView = "_ListItemPartial";

            var myViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { { partialView, myHeader.MyChildPropertiesList } };
            myViewData.Model = myHeader;

            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<Child> MyChildPropertiesList { get; set; } = new List<Child>();
    }

    public class Child
    {
        public int Id { get; set; }
        public int HeaderId { get; set; }
        public string MyChildProperty { get; set; }
    }
}

My 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="AddItem()">Add Child Item</a>
</div>

<br />

<div>
    <div><b>MyHeaderProperty value:</b> @Model.MyHeader.MyHeaderProperty</div>
    <br />
    <div class="font-weight-bold">Child Items</div>
    <br />
    <div id="LineItemsPartial">
        <partial name="_ListItemPartial" model="@Model" />
    </div>

</div>

<script type="text/javascript">
    function AddItem() {
        var model = @Json.Serialize(Model.MyHeader);
        alert(JSON.stringify(model));
        $.ajax({
            type: "GET",
            url: "?handler=AddNewChildItem",
            data: JSON.stringify(model),
            dataType: "json",
            success: function (result) {
                alert("Success");
                $('#LineItemsPartial').html(result);
            },
            failure: function (result) {
                alert("Failed");
            }
        });
    }
</script>

My Partial View

@model IndexModel


<table>
    @foreach (var myChildItem in Model.MyHeader.MyChildPropertiesList)
    {
        <tr>
            <td>@myChildItem.HeaderId</td>
            <td>@myChildItem.MyChildProperty</td>
        </tr>
    }
</table>

Any help is really appreciated.

1 Answers1

0

From your code design,you have some mistakes below:

1.It is not a good way to use FromBody in get method.If you want to send data to the backend by get request,you need to send model by query string in the url.What you did should be a Post request way.

Reference:

https://stackoverflow.com/a/983458/11398810

2.The ViewData of the partial view result is type of Header.But your partial view needs type of IndexModel

Here is a working demo:

Index.cshtml:

@page
@model IndexModel
<div>
    <a class="btn btn-sm btn-info text-white" onclick="AddItem()">Add Child Item</a>
</div>
<br />
<div>
    <div><b>MyHeaderProperty value:</b> @Model.MyHeader.MyHeaderProperty</div>
    <br />
    <div class="font-weight-bold">Child Items</div>
    <br />
    <div id="LineItemsPartial">
        <partial name="_ListItemPartial" model="@Model" />
    </div>
    @Html.AntiForgeryToken()  @*add this*@
</div>

<script type="text/javascript">
    function AddItem() {
        var model = @Json.Serialize(Model.MyHeader);
        $.ajax({
            type: "Post",      //change this...
            url: "?handler=AddNewChildItem",
            data: JSON.stringify(model),
            
            //add the following contentType and headers..
            contentType: "application/json",  
            headers: {
                RequestVerificationToken: $('input:hidden[name="__RequestVerificationToken"]').val()
            },
            dataType: "html",     //midify this..
            success: function (result) {
                $('#LineItemsPartial').html(result);
            },
            failure: function (result) {
                alert("Failed");
            }
        });
    }
</script>

Index.cshtml.cs:

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 PartialViewResult OnPostAddNewChildItem([FromBody] Header myHeader)
    {
        if (myHeader.MyChildPropertiesList == null)
            myHeader.MyChildPropertiesList = new List<Child>();

        myHeader.MyChildPropertiesList.Add(new Child
        {
            Id = 4,
            HeaderId = myHeader.Id,
            MyChildProperty = "ChildTest4"
        });

        //add this line....
        var data = new IndexModel(_logger);
        data.MyHeader = myHeader;

        var partialView = "_ListItemPartial";

        var myViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { { partialView, myHeader.MyChildPropertiesList } };
        myViewData.Model = data;   //change here..

        var partialViewResult = new PartialViewResult()
        {
            ViewName = partialView,
            ViewData = myViewData,
        };     
        return partialViewResult;
    }
}

Result:

enter image description here

Rena
  • 14,556
  • 3
  • 15
  • 44