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 >
<h4>Search By</h4>
<div >
<div >
<label asp-for="FirstMidName"></label>
<input name="FirstMidName" type="text" value="@ViewData["CurrentFilter"]"/>
<br />
<span asp-validation-for="FirstMidName" ></span>
</div>
<div >
<label asp-for="LastName"></label>
<input name="LastName" type="text" value="@ViewData["CurrentFilter2"]"/>
<br />
<span asp-validation-for="LastName" ></span>
</div>
<div >
<label asp-for="EnrollmentDateFrom"></label>
<input name="EnrollmentDateFrom" type="date" value="@ViewData["CurrentFilter3"]"/>
<br />
<span asp-validation-for="EnrollmentDateFrom" ></span>
</div>
<div >
<label asp-for="EnrollmentDateUntil"></label>
<input name="EnrollmentDateUntil" type="date" value="@ViewData["CurrentFilter4"]"/>
<br />
<span asp-validation-for="EnrollmentDateUntil" ></span>
</div>
<input type="submit" value="Search" />
</div>
</div>
</form>
<div >
<a asp-action="Create" >Create New [ ]</a>
<a asp-action="Index" >Back to List</a>
</div>
<form asp-action="Index" asp-controller="Students" method="post">
<table >
<thead>
<tr >
<th >
@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 >
@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 asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<ul >
@for(int i=1; i<=Model.pageCount; i )
{
<li >
@if(i != Model.currentPageIndex)
{
<a href="javascript: PagerClick(@i);">@i</a>
}
else
{
<a >@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
CodePudding user response:
It seems your Model.StundentList is null. It's a good idea to check for null before inserting it into the loop.
CodePudding user response:
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.