Friday, August 31, 2018

ASP.NET Core MVC: How to load a partial view

 Introduction


This article is going to describe how to show a partial view when a button clicks. The sample application shows the search form with all the students records. When search button clicks, it's going to only render student list from students partial view, search form is not getting rendered again. This is a small example of how to load a partial view for a user action.You can use this as a sample and handle a more complex scenario.

Background



Create ASP.NET Core project


Let's create a ASP.NET Core project from Visual Studio, Let's check what is the Visual Studio version in your development environment, if it's not up to date, will update it to the latest version.
Open Visual Studio, from menu go to Help -> Check for Updates It will show Visual Studio is up to date and latest version is Visual Studio 2017 - 15.8.1





















Let's create new solution from Visual Studio, Click on File -> New -> Project, you will get a window as shown below, click on Visual C# -> .NET Core and select ASP.NET Core Web Application from available templates. You can give a name and a location for the solution

You can select a project template from below screen, let's go with Web Application (Model - View - Controller) since we are going to create a solution with MVC pattern, In this sample we are creating the project with the latest .NET Core version, ASP.NET Core 2.1


Add Student Model


You will get separate folders for Models, Views and Controllers in your project. Let's create a model class called Student as below


namespace ajaxPartial.Models
{
    public class Student
    {

        public string Name { get; set; }
        public int CourseId { get; set; }
        public string Course { get; set; }
        public string Lab { get; set; }
        public double Marks { get; set; }
     }
}


Let's create a method to return list of students



public static List<Student> GetStudents () 


 var students = new List<Student>() {
                new Student { Name = "Hank Aaron", CourseId = 1, Course = "Computer Architecture", Lab = "Lab 01", Marks = 84},
                new Student{ Name = "Alfred Adler", CourseId = 2, Course = "Database Systems", Lab = "Lab 02", Marks = 70 }, 
                new Student { Name = "Conrad Aiken", CourseId = 1, Course = "Computer Architecture", Lab = "Lab 03", Marks = 73 }, 
                new Student { Name = "Buzz Aldrin", CourseId = 3, Course = "Data Structure and Algorithms", Lab = "Lab 04", Marks = 92 },
                new Student { Name = "Susan Anthony", CourseId = 4, Course = "Software Engineering", Lab = "Lab 01", Marks = 65 },
                new Student { Name =  "Norman Ralph Augustine", CourseId = 2, Course = "Database Systems", Lab = "Lab 03", Marks = 59},
                new Student { Name = "Andy Bathgate", CourseId = 1, Course = "Computer Architecture", Lab = "Lab 02", Marks = 80 },
                new Student { Name = "Jimmy Carter", CourseId = 2, Course = "Database Systems", Lab = "Lab 01", Marks = 84 },
                new Student { Name = "Thomas Edison", CourseId = 4, Course = "Software Engineering", Lab = "Lab 04", Marks = 75 },
                new Student { Name = "Thomas Edison", CourseId = 3, Course = "Data Structure and Algorithms", Lab = "Lab 01", Marks = 60 },
                new Student { Name = "William Gladstone", CourseId = 2, Course = "Database Systems", Lab = "Lab 03", Marks = 69 },
                new Student { Name = "Mary Hirsch", CourseId = 2, Course = "Database Systems", Lab = "Lab 01", Marks = 78 },
                new Student { Name = "Derek Jeter", CourseId = 3, Course = "Data Structure and Algorithms", Lab = "Lab 02", Marks = 73 },
                new Student { Name = "Ted Kennedy", CourseId = 3, Course = "Data Structure and Algorithms", Lab = "Lab 03", Marks = 85 },
                new Student { Name = "Steve Lyons", CourseId = 2, Course = "Database Systems", Lab = "Lab 02", Marks = 79 },
                new Student { Name = "Benito Mussolini", CourseId = 4, Course = "Software Engineering", Lab = "Lab 04", Marks = 59 } };

return students; 
}

Change Index method in HomeController


Go to HomeController and change Index method to get list of students and pass it to the Index view.



















public IActionResult Index() 

  List students = Student.GetStudents(); 
  return View(students); 


Add Student list view


You can change the student Index view as below, add search from with student text box and courses drop down




<h1>Search Students</h1>
<br />

<form>
    <div class="form-row">
        <div class="form-group col-md-6">
            <label for="Student">Student</label>
            <input type="text" id="student" placeholder="Student" class="form-control">
        </div>
        <div class="form-group col-md-6">
            <label for="Course">Course</label>
            <select class="form-control">
                <option value="1">Computer Architecture</option>
                <option value="2">Database Systems</option>
                <option value="3">Data Structure and Algorithms</option>
                <option value="4">Software Engineering</option>
            </select>
        </div>
    </div>
    <div class="form-row">
        <div class="form-group col-md-12">
            <input id="btnSearch" type="button" class="btn btn-primary" value="Search"/>
        </div>
    </div>
</form>

Let's add a grid view below the search form, when initial page loads, it will show all the student records,

































<table class="table table-striped">
    <thead>
        <tr>
            <th> Name </th>
            <th> Course </th>
            <th> Lab </th>
            <th> Marks </th>
        </tr>
    </thead>
    <tbody>
        @foreach (var student in Model)
         {
            <tr>
                <td> @student.Name </td>
                <td> @student.Course </td>
                <td> @student.Lab </td>
                <td> @student.Marks </td>
            </tr>
         }
    </tbody>
</table>

Add js file to load students


Let's create javascript file to write js function for Index view and refer it from view as below,








<script src="~/js/index.js"></script>

You can see index.js file as below. Let's write method to execute when search button click using jquery selector







$('#btnSearch').on('click', function (e) { 
  alert(); 
});


Let's run the application, you can see a search form and a list of students as below. When we click on search button, we want to fetch students according to the search criteria.
You can find two ways to do that, load whole page when a button clicks or else refresh only the student list, search form will not be rendered again. We can do that by passing a ajax request and loading a partial view.
In this developed application, search form and student list is available in the same page, let's split the two things into two views and load the second view on a ajax request






















Create a partial view for students


Let's create a partial view to hold list of students and separate students grid from Index view, Go to Views folder and click on Add -> View
In Add MVC View window, add a view name, select List as the view template, select Student as model class, tick on Create as partial view and click on Add button
























You can see _Students partial view as below, It's going to show a list of students in a grid layout







































Change data load methods


You can change GetStudents method by passing a filter parameter, It will filter student list according to Student name and Course





















public static List GetStudents (StudentFilter filters) 

  var students = new List() { 
   new Student { Name = "Hank Aaron", CourseId = 1, Course = "Computer Architecture", Lab = "Lab 01", Marks = 84}, 
   new Student{ Name = "Alfred Adler", CourseId = 2, Course = "Database Systems", Lab = "Lab 02", Marks = 70 }, 
   new Student { Name = "Conrad Aiken", CourseId = 1, Course = "Computer Architecture", Lab = "Lab 03", Marks = 73 }, 
   new Student { Name = "Buzz Aldrin", CourseId = 3, Course = "Data Structure and Algorithms", Lab = "Lab 04", Marks = 92 }, 
   new Student { Name = "Susan Anthony", CourseId = 4, Course = "Software Engineering", Lab = "Lab 01", Marks = 65 }, 
   new Student { Name = "Norman Ralph Augustine", CourseId = 2, Course = "Database Systems", Lab = "Lab 03", Marks = 59}, 
   new Student { Name = "Andy Bathgate", CourseId = 1, Course = "Computer Architecture", Lab = "Lab 02", Marks = 80 }, 
   new Student { Name = "Jimmy Carter", CourseId = 2, Course = "Database Systems", Lab = "Lab 01", Marks = 84 }, 
   new Student { Name = "Thomas Edison", CourseId = 4, Course = "Software Engineering", Lab = "Lab 04", Marks = 75 }, 
   new Student { Name = "Thomas Edison", CourseId = 3, Course = "Data Structure and Algorithms", Lab = "Lab 01", Marks = 60 }, 
   new Student { Name = "William Gladstone", CourseId = 2, Course = "Database Systems", Lab = "Lab 03", Marks = 69 }, 
   new Student { Name = "Mary Hirsch", CourseId = 2, Course = "Database Systems", Lab = "Lab 01", Marks = 78 }, 
   new Student { Name = "Derek Jeter", CourseId = 3, Course = "Data Structure and Algorithms", Lab = "Lab 02", Marks = 73 }, 
   new Student { Name = "Ted Kennedy", CourseId = 3, Course = "Data Structure and Algorithms", Lab = "Lab 03", Marks = 85 }, 
   new Student { Name = "Steve Lyons", CourseId = 2, Course = "Database Systems", Lab = "Lab 02", Marks = 79 }, 
   new Student { Name = "Benito Mussolini", CourseId = 4, Course = "Software Engineering", Lab = "Lab 04", Marks = 59 } }; 

 if (!string.IsNullOrEmpty(filters.Student)) 
   students = students.Where(s => s.Name.ToLower().Contains(filters.Student.ToLower())).ToList(); 

 if (filters.CourseId != 0) 
   students = students.Where(s => s.CourseId == filters.CourseId).ToList(); 

 return students; 

 } 

Create StudentFilter model class as follows, we have to pass string value in text box control and selected drop down value 


















namespace ajaxPartial.Models 


   public class StudentFilter 
   { 

       public string Student { get; set; } 
       public int CourseId { get; set; } 

    } 
  } 

Change Index action method implementation to call GetStudents method,
In the page load it's going to call student load method with empty parameters (All option is selected in dropdown & empty textbox)
When click on Search button, call student load method with parameters and pass it to the _Students partial view


























namespace ajaxPartial.Controllers 

  public class HomeController : Controller 
  { 
     public IActionResult Index() 
     { 
       List students = Student.GetStudents(new StudentFilter()); 
       return View(students); 
     } 

     [HttpPost] 
     public IActionResult Students (StudentFilter filters) 
     { 
       List students = Student.GetStudents(filters); 
       return PartialView("_Students", students); 
     } 
 } 
}

You can see _Students partial view as below, It expects list of Students and render them in a table







































@model IEnumerable<ajaxPartial.Models.Student>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Name)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Course)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Lab)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Marks)
            </th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Course)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Lab)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Marks)
            </td>
        </tr>
}
    </tbody>
</table>

When click on search button, it'll load list of students from _Students partial view into this div tag. Let's see how we can do that from JavaScript function 



































@using ajaxPartial.Models;

@model List<Student>

<h1>Search Students</h1>
<br />

<form>
    <div class="form-row">
        <div class="form-group col-md-6">
            <label for="Student">Student</label>
            <input type="text" id="student" placeholder="Student" class="form-control">
        </div>
        <div class="form-group col-md-6">
            <label for="Course">Course</label>
            <select class="form-control" id="course">
                <option value="0">All</option>
                <option value="1">Computer Architecture</option>
                <option value="2">Database Systems</option>
                <option value="3">Data Structure and Algorithms</option>
                <option value="4">Software Engineering</option>
            </select>
        </div>
    </div>
    <div class="form-row">
        <div class="form-group col-md-12">
            <input id="btnSearch" type="button" class="btn btn-primary" value="Search" />
        </div>
    </div>
</form>

<div id="students"> </div>

<script src="~/js/index.js"></script>

Load partial view from javascript method


Go to index.js file, load student list when page loads, we can call it from document.ready event
When click on search button, we can issue a ajax request with student text box and course dropdown values. 
When it succeeds, load _Students partial view into students div tag. We can identify error and stack trace information if anything bad happens
In Ajax request, pass the Controller - Action url, type of the request as POST, filter data as a JSON object and the response in form of a html string since action method returns a partial view 
We can specify the async parameter for the Ajax request, by default it's async - true, If we want to make a synchronous request we can set async to false, sometimes browser can be blocked in a async request, so we have to modify it accordingly
In Ajax request, we can set cache options as well. We can set cache - true for GET & HEAD requests only, If we want to cache the result of a method, we can set cache attribute to true







































$(function () { 
  GetStudents(); 
}); 


$('#btnSearch').on('click', function (e) { 
  var filters = { 
      student: $('#student').val(), 
      courseId: $('#course').val() 
    }; 
  GetStudents(filters); 
}); 


function GetStudents(filters) { 
   $.ajax({ 
         url: '/Home/Students', 
         type: 'POST', 
         cache: false, 
         async: true, 
         dataType: "html", 
         data : filters 
    })
   .done(function (result) { 
      $('#students').html(result); 
    }).fail(function (xhr) { 
         console.log('error : ' + xhr.status + ' - ' + xhr.statusText + ' - ' +                       xhr.responseText); 
     }); 
}

Let's run the application and see what happens, it shows search form and student list partial view when the page loads































Let's try to filter students from a course and student name, when click on Search button it's going to load the partial view with filtered data










Download


TechNet Gallery


You can download the source code from TechNet Gallery, ASP.NET Core : loading a partial view

GitHub


You can clone the source code from GitHub, ajax-partialview


Conclusion


In this article, we used ASP.NET Core MVC to develop an application and load a partial view when a button clicks. In the main view, search form is not getting rendered again when search button clicks, it only renders the partial view from a AJAX request.


References



No comments:

Post a Comment