skip to Main Content

i was following this tutorial about paginate. it all worked, but if i add some sorting & filtering from my old code, it doesn’t work. and the error says

NullReferenceException: Object reference not set to an instance of an object.

this is my controller

public async Task<IActionResult> Index()
    {
        return View(await GetStudentList(1));
    }

    [HttpPost]
    public async Task<IActionResult> Index(int currentPageIndex)
    {
        return View(await GetStudentList(currentPageIndex));
    }

    // GET: Students

    public IActionResult IndexProses(string sortOrder, StudentVM model)
    {
        ViewData["CurrentSort"] = sortOrder;
        ViewData["NameSortParm"] = sortOrder == "name" ? "name_desc" : "name";
        ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
        ViewData["FirstSortParm"] = String.IsNullOrEmpty(sortOrder) ? "first_desc" : "";

        ViewData["CurrentFilter"] = model.FirstMidName;
        ViewData["CurrentFilter2"] = model.LastName;
        ViewData["CurrentFilter3"] = model.EnrollmentDateFrom;
        ViewData["CurrentFilter3"] = model.EnrollmentDateUntil;

        var students = from s in _context.Students
                       select s;

        // sorting // 
        students = sortOrder switch
        {
            "name" => students.OrderBy(s => s.LastName),// asc last name
            "name_desc" => students.OrderByDescending(s => s.LastName),//desc last name
            "first_desc" => students.OrderByDescending(s => s.FirstMidName),// desc first name
            "Date" => students.OrderBy(s => s.EnrollmentDate),// asc date
            "date_desc" => students.OrderByDescending(s => s.EnrollmentDate),// desc date
            _ => students.OrderBy(s => s.FirstMidName),// asc first name
        };

        // filtering
        if (model.EnrollmentDateFrom != null && model.EnrollmentDateUntil != null)
        {
            students = students.Where(s => s.EnrollmentDate >= model.EnrollmentDateFrom && s.EnrollmentDate <= model.EnrollmentDateUntil);
        }
        if (!String.IsNullOrEmpty(model.LastName))
        {
            students = students.Where(s => s.LastName.Contains(model.LastName));
        }
        if (!String.IsNullOrEmpty(model.FirstMidName))
        {
            students = students.Where(s => s.FirstMidName.Contains(model.FirstMidName));
        }
        return View("Index", model);
    } 

    private async Task<StudentVM> GetStudentList(int currentPage)
    {
        int maxRowsPerPage = 5;
        StudentVM model = new StudentVM();
        model.StundentList = await (from s in _context.Students select s)
            .Skip((currentPage - 1) * maxRowsPerPage)
            .Take(maxRowsPerPage).ToListAsync();

        double pageCount = (double)((decimal)_context.Students.Count() / Convert.ToDecimal(maxRowsPerPage));

        model.pageCount = (int)Math.Ceiling(pageCount);
        model.currentPageIndex = currentPage;
        return model;
    }

my assumption is because filtering & sorting is using Get method, but paging is using Post method. but i dont know how to fix it:(, here’s the error details. The Index.cshtml file:

    @model ContosoUniversity.Models.SchoolViewModels.StudentVM


@{
    ViewData["Title"] = "Students";
    //List<Student> students = ViewBag.students; 
}

<style>
    table{
        margin-top: 20px;
    }

    .table a{
    text-decoration: none;
    }

    /*.opsi a:hover{
    text-decoration: underline;
    }*/
    
    h2{
        margin-bottom: 20px;
    }

    .tbl{
        display: flex;
        gap: 1rem;
    }

    .box{
        display: flex;
        gap: 1rem;
        margin-bottom: 10px;
    }
</style>
<h2>Contoso University - Students</h2>

<form asp-action="IndexProses" asp-antiforgery="false" method="get">
    <div class="form-actions no-color">
        <h4>Search By</h4>
        <div class="box">
            <div class="search">
                <label asp-for="FirstMidName"></label>
                <input name="FirstMidName" type="text" value="@ViewData["CurrentFilter"]"/>
                <br />
                <span asp-validation-for="FirstMidName" class="text-danger"></span>
            </div>
            
            <div class="search">
                <label asp-for="LastName"></label>
                <input name="LastName" type="text" value="@ViewData["CurrentFilter2"]"/>
                <br />
                <span asp-validation-for="LastName" class="text-danger"></span>
            </div>

            <div class="search">
                <label asp-for="EnrollmentDateFrom"></label>
                <input name="EnrollmentDateFrom" type="date" value="@ViewData["CurrentFilter3"]"/>
                <br />
                <span asp-validation-for="EnrollmentDateFrom" class="text-danger"></span>
            </div>

            <div class="search">
                <label asp-for="EnrollmentDateUntil"></label>
                <input name="EnrollmentDateUntil" type="date" value="@ViewData["CurrentFilter4"]"/>
                <br />
                <span asp-validation-for="EnrollmentDateUntil" class="text-danger"></span>
            </div>

            <input type="submit" value="Search" class="btn btn-primary" />
        </div>
    </div>
</form>


<div class="tbl">
    <a asp-action="Create" class="btn btn-primary">Create New [+]</a>
    <a asp-action="Index" class="btn btn-info text-white">Back to List</a>
</div>

<form asp-action="Index" asp-controller="Students" method="post">
    <table class="table table-hover">
        <thead>
            <tr class="table-light">
                <th class="table-light">
                    @Html.ActionLink("First Name", "IndexProses", new { sortOrder = ViewBag.FirstSortParm, FirstMidName = Model.FirstMidName, LastName = Model.LastName, EnrollmentDateFrom = Model.EnrollmentDateFrom, EnrollmentDateUntil = Model.EnrollmentDateUntil })
                </th>
                <th>
                @Html.ActionLink("Last Name", "IndexProses", new { sortOrder = ViewBag.NameSortParm, FirstMidName = Model.FirstMidName, LastName = Model.LastName, EnrollmentDateFrom = Model.EnrollmentDateFrom, EnrollmentDateUntil = Model.EnrollmentDateUntil })
                </th>
                <th>
                @Html.ActionLink("Enrollment Date", "IndexProses", new { sortOrder = ViewBag.DateSortParm, FirstMidName = Model.FirstMidName, LastName = Model.LastName, EnrollmentDateFrom = Model.EnrollmentDateFrom, EnrollmentDateUntil = Model.EnrollmentDateUntil })
                </th>
                <th>Opsi</th>
            </tr>
        </thead>
        <tbody class="opsi">
            @foreach (var item in Model.StundentList)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.FirstMidName)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.LastName)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.EnrollmentDate)
                    </td>
                    <td>
                        <a class="btn btn-warning text-white" asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                        <a class="btn btn-info text-white" asp-action="Details" asp-route-id="@item.ID">Details</a> |
                        <a class="btn btn-danger" asp-action="Delete" asp-route-id="@item.ID">Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <ul class="pagination">
        @for(int i=1; i<=Model.pageCount; i++)
        {
            <li class="page-item">
                @if(i != Model.currentPageIndex)
                {
                    <a class="page-link" href="javascript: PagerClick(@i);">@i</a>
                }
                else
                {
                    <a class="page-link">@i</a>
                }
            </li>
        }
    </ul>
    <input type="hidden" id="hfCurrentPageIndex" name="currentPageIndex"/>
</form>

<script type="text/javascript">
    function PagerClick(index)
    {
        document.getElementById("hfCurrentPageIndex").value=index;
        document.forms[0].submit();
    }
</script>

here’s the ViewModel

 public class StudentVM : IValidatableObject
    {
        public int currentPageIndex { get; set; }
        public int pageCount { get; set; }
        public List<Student> StundentList { get; set; }

        [Display(Name = "Last Name :")]
        public string LastName { get; set; }

        [Display(Name = "First Name :")]
        public string FirstMidName { get; set; }

        [DataType(DataType.Date)]
        [Display(Name = "Date From :")]
        public DateTime? EnrollmentDateFrom { get; set; } // ? (NULLABLE)

        [DataType(DataType.Date)]
        [Display(Name = "Until :")]
        public DateTime? EnrollmentDateUntil { get; set; } // ? (NULLABLE)

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (FirstMidName == null)
            {
                yield return new ValidationResult("input first name!", new[] { "FirstMidName" });
                //Memberi validation jika sebuah kolom pencarian tidak diisi!
            }
            
            if (LastName == null)
            {
                yield return new ValidationResult("input last name!", new[] { "LastName" });
                //Memberi validation jika sebuah kolom pencarian tidak diisi!
            }

            if (EnrollmentDateFrom == null)
            {
                yield return new ValidationResult("input date from!", new[] { "EnrollmentDateFrom" });
                //Memberi validation ke variable yang dituju!
            }
            if (EnrollmentDateUntil == null)
            {
                yield return new ValidationResult("input date until!", new[] { "EnrollmentDateUntil" });
                //Memberi validation ke variable yang dituju!
            }
        }
    }

for the filtering & sorting tutorial, im following this tutorial

2

Answers


  1. It seems your Model.StudentList is null. It’s a good idea to check for null before inserting it into the loop.

    Login or Signup to reply.
  2. You need to instantiated model.StundentList and fill it first:

    public IActionResult IndexProses(string sortOrder, StudentVM model)
    {
        ......
        model.StundentList = new List<Student>();
        foreach (var student in students)
        {
            model.StundentList.Add(student);
        }
        return View("Index", model);
    }
    

    In addition, your code seems to have logic problems, perhaps because you haven’t finished it yet.

    I suggest you use the method in this tutorial for paging.

    Update:

    Because you submit the forms[0] when you click on the page number, the post method of Index is not called.

    Change

    document.forms[0].submit();
    

    to

    document.forms[1].submit();
    

    This allows you to call the post method of Index.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search