How to refresh data displayed in ViewComponent's default View : ASP.NET MVC Core

sama clif 0 Reputation points
2023-09-09T21:21:33.3333333+00:00

I have a razor view that is divided into two columns. The column on the left contains a list of bootstrap list-group-items ( job cards). On the right is a larger column to display the full details of the active job card. The right column is simply a viewcomponent which takes as parameter a job entity and render it details on the default view.

Here is my main view

@model IEnumerable<JobListing>

<div class=" d-flex justify-content-center col-12 row my-3 mx-0 p-0 row position-relative">

<!--collection of Listing cards -->

<div style=" " class=" d-flex justify-content-start col-sm-12 col-lg-5 col-xl-4  m-0 p-0 pe-4">

    <div id="jobList" class="list-group col-12 m-0 p-0  border-0 ">

        @foreach (var listing in Model)

        {

           

            <div id="listing-@count" class="list-group-item list-group-item-action " data-bs-toggle="list" href="#listing-@count">

                <!-- Listing Card -->

            </div>

            count++;

        }

    </div>

</div>

<!--Job Details-->

<div style="" class="s p-1">

    <div id="jobDetail" class=" h-auto border border-1 border-primary rounded rounded-3 align-items-start ">

        @await Component.InvokeAsync("JobDetail", new {joblisting = Model.ElementAt(0)})

    </div>

</div>

</div>

Initially the first job in the list is loaded by the viewcomponent. Now, I have added click eventListener to each card to capture when it's selected and then pass a serialized version of the active joblisting object to this ajax method LoadJobDetail(...)

<script>
     const divItems = document.querySelectorAll('.list-group-item');
     divItems.forEach(function (div) {
         div.addEventListener('click', function () {
             var job = this.getAttribute('data-job');
             LoadJobDetail(job);
         });
     });
     function LoadJobDetail(jobListing) {
         $.ajax({
             type: "GET",
             url: "customer/Home/LoadJobDetail",
             data: { job: JSON.stringify(jobListing) },
             success: function (response) {
                 // Refresh viewcomponent data
             },
             error: function (error) {
                 console.log("operation failed...", error);
             }
         });
     }
 </script>

The ajax method calls this action method which in turn invokes the view component and pass the job...

[HttpGet]
 public IActionResult LoadJobDetail(string job)
 {
     // Convert string to joblisting
     JobListing jobDetail = JsonConvert.DeserializeObject<JobListing>(job);
     if (jobDetail != null)
     {
         var result = ViewComponent("JobDetail", new { jobListing = jobDetail });
         return Json(new { response = result, success = true, message = "Job detail successfully loaded" });
     }
     else
     {
         return Json(new { response = "", success = false, message = "could not load the selected job listing" });
     }
 }

And here is my ViewComponent class

 public async Task<IViewComponentResult> InvokeAsync(JobListing jobListing)
 {
     // return the view
     return View(jobListing);
 }

The view for my ViewComponent expects as model a JobListing object. So far all the code till the step of invoking the ViewComponent works fine. I added a breakpoint on the Default.cshtml for the ViewComponent and the properties are being set. But the data in View never refreshes. Any help on how to display the details for selected job? Perhaps am using the wrong approach. I've thought of using partial view instead but doesn't sound reasonable.

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,482 questions
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,254 questions
ASP.NET
ASP.NET
A set of technologies in the .NET Framework for building web applications and XML web services.
3,330 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,423 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 58,441 Reputation points
    2023-09-10T01:52:33.4833333+00:00

    Your Ajax call returns a json object. You need to write JavaScript to duplicate what the view component does. You other option is for the Ajax call to return html instead of the json. You could use $.load() or insert the html response.

    as it’s a dynamic page, I’d skip the view detail view component altogether and just use JavaScript.

    note: you are doing an Ajax get, so only query string parameters are supported. The request should be:

             data: { job: jobListing },
    

  2. sama clif 0 Reputation points
    2023-09-10T08:03:37.2633333+00:00

    I created a partial view with same code and model as that in my Default.cshtml for the previous ViewComponent. Then modified the action method to return the partial view with it's model like so

    [HttpGet]

    public IActionResult LoadJobDetail(string job)

    {

      // Convert string to joblisting
    
      JobListing jobDetail = JsonConvert.DeserializeObject<JobListing>(job);
    
      return PartialView("_JobDetailsPartial", jobDetail);
    

    }

    And then modified the ajax call to load the result inside the jobDetailContainer div

    function LoadJobDetail(jobListing) {
        
        $.ajax({
            type: "GET",
            url: "customer/Home/LoadJobDetail",
            data: { job: JSON.stringify(jobListing) },
            success: function (response) {
                    
                   $('#jobDetail').html(response);
                console.log(response);
            },
            error: function (error) {
                console.log("operation failed...", error);
            }
       });
    

    Everything else remain the same. Don't know if it's the right approach but it looks cleaner than trying to convert a viewComponentResult into html code.