Reputation: 525
Friends, I have implemented a solution type ASP.NetCore with a project MVC. I have a view in which I used https://github.com/cloudscribe/cloudscribe.Web.Pagination for pagination. **Honestly I took the example and used it. But I don't get the detail about this code example.
The problem that I have now is that, I have to include filters, like datepicker range. So I am using bootstrap datepicker. But the pagination stopped working.
The pagination gets this parameters in querytrings to work: pageNumber, pageSize and query. When I send the request of the filter date, I can get the dates selected in the controller, but the parameters of pagination get in null.
This is an URL example with pagination working fine: http://localhost/pager?query=1&pagesize=10&pageNumber=2
This is an URL when I send the request in the button 'Apply' with dates range, and pagination died without its parameters like 'query': http://localhost/pager?startDate=11/04/2019&endDate=11/11/2019
I suppose I have to send the current querystring in the request too, but I'm not sure, I'm kind of new at this technology. Thanks for any help.
My view →
@using (Html.BeginForm("Details", "Movements", routeValues: new { pageNumber = @Model.UserMovementsResults.PageNumber, pageSize = @Model.UserMovementsResults.PageSize, query = @Model.Query }, FormMethod.Get))
{
<br />
<div style="border: 2px solid #dee2e6;padding: 5px;width: 50%;">
<br />
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
@Html.TextBoxFor(model => model.StartDateFilter, "{0:d MMM yyyy}", new
{
id = "StartDateFilter",
@class = "input-sm form-control",
@readonly = "readonly"
})
<span class="input-group-addon"> To </span>
@Html.TextBoxFor(model => model.EndDateFilter, "{0:d MMM yyyy}", new
{
id = "EndDateFilter",
@class = "input-sm form-control",
@readonly = "readonly"
})
</div>
<br />
<input type="submit" value="Apply" class="btn btn-primary" name="Apply" />
</div>
<br />
<br />
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Date)
</th>
<th>
@Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Description)
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.UserMovementsResults.Data)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Date)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</tbody>
</table>
<div>
<cs-pager cs-paging-pagesize="@Model.UserMovementsResults.PageSize"
cs-paging-pagenumber="@Model.UserMovementsResults.PageNumber"
cs-paging-totalitems="@Model.UserMovementsResults.TotalItems"
cs-pagenumber-param="pageNumber"
cs-show-first-last="true"
cs-suppress-empty-nextprev="true"
cs-remove-nextprev-links="false"
cs-suppress-inactive-firstlast="true"
cs-first-page-text="First"
cs-last-page-text="Last"
cs-pager-li-current-class="active"
cs-pager-li-non-active-class="disabled"
asp-controller="Movements"
asp-route-query="@Model.Query"
asp-route-pagesize="@Model.UserMovementsResults.PageSize"
asp-route-startDateFilter="@Model.StartDateFilter.GetValueOrDefault()"
asp-route-endDateFilter="@Model.EndDateFilter.GetValueOrDefault()"
asp-action="Details" cs-preserve-ambient-querystring="true"></cs-pager>
</div>
}
My Controller (I've tried to set the method HttpGet and HttpPost) →
[HttpGet]
public async Task<IActionResult> Details(int? pageNumber, int? pageSize, int? query, string startDate, string endDate)
{
if (query == null)
{
return NotFound();
}
DateTime startDateFilter = DateTime.Now.StartOfWeek(DayOfWeek.Monday);
DateTime endDateFilter = DateTime.Now.EndOfWeek(DayOfWeek.Monday);
var userMovements = await GetUserMovements(user.Id, pageNumber, pageSize, query, startDateFilter, endDateFilter);
return View(userMovements);
}
}
My ViewModel →
public class UserMovementsViewModel
{
private DateTime? endDateFilter;
public UserMovementsViewModel()
{
UserMovementsResults = new PagedResult<UserMovementsResult>();
}
public string Query { get; set; } = string.Empty;
[Key]
public int Id { get; set; }
public int UserId { get; set; }
public PagedResult<UserMovementsResult> UserMovementsResults { get; set; } = null;
public DateTime? StartDateFilter { get; set; }
public DateTime? EndDateFilter
{
get => endDateFilter;
set
{
if (value != null)
{
endDateFilter = value;
endDateFilter = endDateFilter.Value.AddHours(23).AddMinutes(59).AddSeconds(59);
}
}
}
}
public class UserMovementsResult
{
public DateTime Date { get; set; }
public string Description { get; set; }
}
Upvotes: 0
Views: 2502
Reputation: 525
If anyone needs this too, here is how I got it → I was missing the setting of the parameters in the controller with ViewBag. Like this → ViewBag.StartDateFilter = starDate; Otherwise, It was becoming at null always, when I tried to change at another page. I don't why. I used a hidden field too to save the "query" (in my case this is the user id) because when I sent the request submit in the button, this was losing its value too. What a mess !!
Here is a minified version
View:
<script src="~/lib/bootstrap/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>
<form class="form-inline" role="form" asp-controller="Movements" asp-action="Details" method="get" asp-antiforgery="false" asp-route-query="@ViewBag.Query">
<div>
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
@Html.TextBox("startDate", null, new
{
id = "startDate",
@class = "input-sm form-control",
@readonly = "readonly"
})
<span class="input-group-addon"> To </span>
@Html.TextBox("endDate", null, new
{
id = "endDate",
@class = "input-sm form-control",
@readonly = "readonly"
})
</div>
<button asp-route-query="@ViewBag.Query" type="submit" value="Filter" name="Filter">Apply</button>
@Html.Hidden("Query", (object)ViewBag.Query)
</div>
</form>
<br />
<table>
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Date)
</th>
<th>
@Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Description)
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.UserMovementsResults.Data)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Date)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</tbody>
</table>
<div>
<cs-pager cs-paging-pagesize="@Model.UserMovementsResults.PageSize"
cs-paging-pagenumber="@Model.UserMovementsResults.PageNumber"
cs-paging-totalitems="@Model.UserMovementsResults.TotalItems"
cs-pagenumber-param="pageNumber"
asp-controller="Movements"
asp-action="Details"
asp-route-query="@ViewBag.Query"
asp-route-pagesize="@Model.UserMovementsResults.PageSize"
cs-preserve-ambient-querystring="true"
asp-route-startDate="@ViewBag.StartDateFilter"
asp-route-endDate="@ViewBag.EndDateFilter">
</cs-pager>
</div>
Controller:
[HttpGet]
public async Task<IActionResult> Details(int? pageNumber, UserMovementsViewModel userMovementsViewModel)
{
userMovementsViewModel.StartDateFilter = DateTime.ParseExact(userMovementsViewModel.StartDate, "dd/MM/yyyy", CultureInfo.InvariantCulture);
userMovementsViewModel.EndDateFilter = DateTime.ParseExact(userMovementsViewModel.EndDate, "dd/MM/yyyy", CultureInfo.InvariantCulture).SetEndOfDay();
var userMovements = await GetUserMovements(pageNumber, userMovementsViewModel).ConfigureAwait(true);
ViewBag.StartDateFilter = userMovementsViewModel.StartDateFilter.Value.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
ViewBag.EndDateFilter = userMovementsViewModel.EndDateFilter.Value.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
ViewBag.Query = userMovementsViewModel.Query;
return View(userMovements);
}
My Class:
public class UserMovementsViewModel
{
public UserMovementsViewModel()
{
UserMovementsResults = new PagedResult<UserMovementsResult>();
}
public string Query { get; set; } = string.Empty;
public PagedResult<UserMovementsResult> UserMovementsResults { get; set; } = null;
public DateTime? StartDateFilter { get; set; }
public DateTime? EndDateFilter { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
}
Upvotes: 0
Reputation: 36655
Here is a simple workaround like below:
1.add the following component in _ViewImports.cshtml:
@using cloudscribe.Web.Pagination
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper "*, cloudscribe.Web.Pagination"
2.Model:
public class UserMovements
{
public string Name { get; set; } = string.Empty;
public DateTime Date { get; set; } = DateTime.UtcNow;
public string Description { get; set; } = string.Empty;
}
public class ViewByDateViewModel
{
public ViewByDateViewModel()
{
UserMovements = new PagedResult<UserMovements>();
}
public PagedResult<UserMovements> UserMovements { get; set; }
public string[] Date { get; set; }
}
3.View(ViewByDate.cshtml):
@using System.Linq
@model ViewByDateViewModel
<form class="form-inline" role="form" asp-controller="Home" asp-action="ViewByDate" method="get" asp-antiforgery="false">
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
@Html.TextBox("startDate", null, new
{
id = "startDate",
@class = "input-sm form-control",
})
<span class="input-group-addon"> To </span>
@Html.TextBox("endDate", null, new
{
id = "endDate",
@class = "input-sm form-control",
})
</div>
<input type="submit" value="Browse" class="btn btn-default" />
</form>
@if (Model.UserMovements.Data.Any())
{
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Date</th>
</tr>
</thead>
<tbody>
@foreach (var product in Model.UserMovements.Data)
{
<tr>
<td>@product.Name</td>
<td>@product.Date</td>
</tr>
}
</tbody>
</table>
<cs-pager cs-paging-pagesize="@Model.UserMovements.PageSize"
cs-paging-pagenumber="@Model.UserMovements.PageNumber"
cs-paging-totalitems="@Model.UserMovements.TotalItems"
cs-pagenumber-param="page"
asp-controller="Home"
asp-action="ViewByDate"
asp-route-categories="@Model.Date.ToCsv()"
asp-route-pagesize="@Model.UserMovements.PageSize"
cs-first-page-text="First"
cs-last-page-text="Last"
cs-previous-page-text="Prev"
cs-next-page-text="Next"></cs-pager>
}
@section Scripts
{
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function () {
$("#startDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' });
$("#endDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' })
});
</script>
}
4.Controller:
public class HomeController : Controller
{
private const int DefaultPageSize = 10;
private List<UserMovements> allMovements = new List<UserMovements>();
public HomeController()
{
InitializeMovements();
}
private void InitializeMovements()
{
// Create a list of Movements.
for (var i = 0; i < 527; i++)
{
var userMovements = new UserMovements();
userMovements.Name = "UserMovements " + (i + 1);
var categoryIndex = i % 4;
if (categoryIndex > 2)
{
categoryIndex = categoryIndex - 3;
}
userMovements.Date = DateTime.Now.AddDays(i);
allMovements.Add(userMovements);
}
}
public IActionResult ViewByDate(string startDate, string endDate, int? page)
{
string[] dates = { startDate, endDate };
List<UserMovements> filtered;
var currentPageNum = page.HasValue ? page.Value : 1;
var offset = (DefaultPageSize * currentPageNum) - DefaultPageSize;
var model = new ViewByDateViewModel();
model.Date = dates ?? new string[0];
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
if (startDate == null && endDate == null)
{
filtered = this.allMovements.ToList();
}
else
{
filtered = this.allMovements
.Where(p => p.Date.Date >= DateTime.Parse(startDate) && p.Date.Date <= DateTime.Parse(endDate))
.ToList();
}
model.UserMovements.Data = filtered
.Skip(offset)
.Take(DefaultPageSize)
.ToList();
model.UserMovements.PageNumber = currentPageNum;
model.UserMovements.PageSize = DefaultPageSize;
model.UserMovements.TotalItems = filtered.Count;
return View(model);
}
}
UPDATE:
1.Model:
public class ViewByDateViewModel
{
private DateTime? endDateFilter;
public ViewByDateViewModel()
{
UserMovements = new PagedResult<UserMovements>();
}
public PagedResult<UserMovements> UserMovements { get; set; }
//public string[] Date { get; set; }
public DateTime? StartDateFilter { get; set; }
public DateTime? EndDateFilter
{
get => endDateFilter;
set
{
if (value != null)
{
endDateFilter = value;
endDateFilter = endDateFilter.Value.AddHours(23).AddMinutes(59).AddSeconds(59);
}
}
}
}
2.View:
@using System.Linq
@model ViewByDateViewModel
<form class="form-inline" role="form" asp-controller="Home" asp-action="ViewByDate" method="get" asp-antiforgery="false">
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
@Html.TextBox("startDate", null, new
{
id = "startDate",
@class = "input-sm form-control",
})
<span class="input-group-addon"> To </span>
@Html.TextBox("endDate", null, new
{
id = "endDate",
@class = "input-sm form-control",
})
</div>
<input type="submit" value="Browse" class="btn btn-default" />
</form>
@if (Model.UserMovements.Data.Any())
{
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Date</th>
</tr>
</thead>
<tbody>
@foreach (var product in Model.UserMovements.Data)
{
<tr>
<td>@product.Name</td>
<td>@product.Date</td>
</tr>
}
</tbody>
</table>
<cs-pager cs-paging-pagesize="@Model.UserMovements.PageSize"
cs-paging-pagenumber="@Model.UserMovements.PageNumber"
cs-paging-totalitems="@Model.UserMovements.TotalItems"
cs-pagenumber-param="page"
asp-controller="Home"
asp-action="ViewByDate"
asp-route-pagesize="@Model.UserMovements.PageSize"
asp-route-startDateFilter="@Model.StartDateFilter"
asp-route-endDateFilter="@Model.EndDateFilter"
cs-first-page-text="First"
cs-last-page-text="Last"
cs-previous-page-text="Prev"
cs-next-page-text="Next"></cs-pager>
}
@section Scripts
{
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function () {
$("#startDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' });
$("#endDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' })
});
</script>
}
3.Controller:
public IActionResult ViewByDate(string startDate, string endDate, int? page)
{
string[] dates = { startDate, endDate };
List<UserMovements> filtered;
var currentPageNum = page.HasValue ? page.Value : 1;
var offset = (DefaultPageSize * currentPageNum) - DefaultPageSize;
var model = new ViewByDateViewModel();
model.StartDateFilter = startDate==null? DateTime.Now:DateTime.Parse(startDate);
model.EndDateFilter = endDate == null ? DateTime.Now : DateTime.Parse(endDate);
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
if (startDate == null && endDate == null)
{
filtered = this.allMovements.ToList();
}
else
{
filtered = this.allMovements
.Where(p => p.Date.Date >= DateTime.Parse(startDate) && p.Date.Date <= DateTime.Parse(endDate))
.ToList();
}
model.UserMovements.Data = filtered
.Skip(offset)
.Take(DefaultPageSize)
.ToList();
model.UserMovements.PageNumber = currentPageNum;
model.UserMovements.PageSize = DefaultPageSize;
model.UserMovements.TotalItems = filtered.Count;
return View(model);
}
if you want to send by url,url would be like:https://localhost:44367/Home/ViewByDate?startdate=11-14-2019&enddate=11-27-2019
Upvotes: 1