Search code examples
c#asp.net-mvcasp.net-core-mvcasp.net-core-viewcomponent

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


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.


Solution

  • Based on @Stilgar suggestion to use partial view, I also found a similar suggestion on Microsoft developers forum and decided to try that and it works. Whether it's the best approach I can't tell as am a beginner.

    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.