asp.net-corerazor-pages

How to return ViewDataDictionary with Partial


I have a razor pages handler

 public IActionResult OnGetAddObjective(string newObjective)
 {
     ViewData["MyTestData"] = "hi";
     return Partial("_ObjectiveRow", new ObjectiveViewModel { ObjectiveText = newObjective });
 }

However, in the _ObjectiveRow partial, the ViewData is not being passed. I can't seem to find an overload that allows this. Which calling the partial on the main page, the ViewData from the parent is accessible.

How do I pass the ViewDataDictionary to the partial?


Solution

  • In ASP.NET Core Razor Pages, the Partial method itself does not support directly passing ViewData. While you cannot directly override the built-in Partial method, you can achieve similar functionality through alternative approaches to ensure that your partial views receive the necessary data.

    Pritial method

    1 Use a custom method PartialView with PartialViewResult to return a partial view:

    namespace PartialDataReturnTest.Pages
    {
        public class TestModel : PageModel
        {
            public void OnGet() { }
    
            public ObjectiveViewModel Model { get; set; }
    
            public IActionResult OnGetPartial(string newObjective)
            {
                var model = new TestModel()
                {
                    Model = new ObjectiveViewModel
                    {
                        ObjectiveText = newObjective
                    }
                };
    
                return PartialView("_ObjectiveRow", model);
            }
    
            [NonAction]
            public virtual PartialViewResult PartialView(string viewName, object model)
            {
                ViewData.Model = model;
                ViewData["MyTestData"] = "hi";
    
                return new PartialViewResult()
                {
                    ViewName = viewName,
                    ViewData = ViewData,
                };
            }
        }
    
        public class ObjectiveViewModel
        {
            public string ObjectiveText { get; set; }
        }
    }
    

    In the Test.cshtml:

    @page
    @model PartialDataReturnTest.Pages.TestModel
    
    <h1>AJAX Partial View Example</h1>
    <button id="loadPartialButton">Load Partial View</button>
    <div id="partialContainer"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
        $(document).ready(function() {
            $('#loadPartialButton').click(function() {
                var data = "Some text";
                $.ajax({
                    url: '@Url.Page("Test", "Partial")', // Adjust URL if necessary
                    type: 'GET',
                    data: {
                        newObjective: data
                    },
                    success: function(result) {
                        $('#partialContainer').html(result);
                    },
                    error: function() {
                        alert('Failed to load partial view.');
                    }
                });
            });
        });
    </script>
    

    Then in the _ObjectiveRow Partial:

    @model PartialDataReturnTest.Pages.TestModel
    @{
        var myTestData = ViewData["MyTestData"];
    }
    
    <div>
        <p>Test Data: @myTestData</p>
        <p>Objective Text: @Model.Model.ObjectiveText</p>
    </div>
    

    My Test Result: result image

    2 Or you can use the Html.PartialAsync in the page, refer to the tutorial Access data from partial views and the code example in this link.

    Sample test:

    public class Test2Model : PageModel
    {
        public ObjectiveViewModel Model { get; set; }
        public void OnGet()
        {
            Model = new ObjectiveViewModel()
            {
                ObjectiveText = "Test text.",
            };
        }
    }
    

    In the Test2.cshtml:

    @page
    @model PartialDataReturnTest.Pages.Test2Model
    
    @{
        var viewData = new ViewDataDictionary(ViewData)
                {
                    ["MyTestData"] = "Hi."
                };
    }
    
    <h1>Partial View Example2</h1>
    
    @await Html.PartialAsync("_ObjectiveRow1", Model, viewData)
    

    In the _ObjectiveRow1 Partial:

    @model PartialDataReturnTest.Pages.Test2Model
    @{
        var myTestData = ViewData["MyTestData"];
    }
    
    <div>
        <p>Test Data: @myTestData</p>
        <p>Objective Text:@Model.Model.ObjectiveText </p>
    </div>
    

    The Test2 Result:

    Test2 image