NOTE: Apart from
(and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.
Friday, 09 August 2024
//Less than a minute
Now that I have a bunch of blog posts the home page was getting rather length so I decided to add a paging mechanism for blog posts.
This goes along with adding full caching for blog posts to make this a quick and efficient site.
See the Blog Service source for how this is implemented; it's really pretty simple using the IMemoryCache.
I decided to use a TagHelper to implement the paging mechanism. This is a great way to encapsulate the paging logic and make it reusable. This uses the pagination taghelper from Darrel O'Neill this is included in the project as a nuget package.
This is then added to the _ViewImports.cshtml file so it is available to all views.
@addTagHelper *,PaginationTagHelper.AspNetCore
In the _BlogSummaryList.cshtml partial view I added the following code to render the paging mechanism.
<pager link-url="@Model.LinkUrl"
hx-boost="true"
hx-push-url="true"
hx-target="#content"
hx-swap="show:none"
page="@Model.Page"
page-size="@Model.PageSize"
total-items="@Model.TotalItems" ></pager>
A few notable things here:
link-url
this allows the taghelper to generate the correct url for the paging links. In the HomeController Index method this is set to that action. var posts = blogService.GetPostsForFiles(page, pageSize);
posts.LinkUrl= Url.Action("Index", "Home");
if (Request.IsHtmx())
{
return PartialView("_BlogSummaryList", posts);
}
And in the Blog controller
public IActionResult Index(int page = 1, int pageSize = 5)
{
var posts = blogService.GetPostsForFiles(page, pageSize);
if(Request.IsHtmx())
{
return PartialView("_BlogSummaryList", posts);
}
posts.LinkUrl = Url.Action("Index", "Blog");
return View("Index", posts);
}
This is set to that URl. This ensures the pagination helper can work for either top level method.
hx-boost
, hx-push-url
, hx-target
, hx-swap
these are all HTMX properties that allow the paging to work with HTMX.
hx-boost="true"
hx-push-url="true"
hx-target="#content"
hx-swap="show:none"
Here we use hx-boost="true"
this allows the pagination taghelper to not need any modifications by intercepting it's normal URL generation and using the current URL.
hx-push-url="true"
to ensure the URL is swapped in the browser's URL history (which allows direct linking to pages).
hx-target="#content"
this is the target div that will be replaced with the new content.
hx-swap="show:none"
this is the swap effect that will be used when the content is replaced. In this case it prevents the normal 'jump' effect which HTMX uses on swapping content.
I also added styles to the main.css in my /src directory allowing me to use the Tailwind CSS classes for the pagination links.
.pagination {
@apply py-2 flex list-none p-0 m-0 justify-center items-center;
}
.page-item {
@apply mx-1 text-black dark:text-white rounded;
}
.page-item a {
@apply block rounded-md transition duration-300 ease-in-out;
}
.page-item a:hover {
@apply bg-blue-dark text-white;
}
.page-item.disabled a {
@apply text-blue-dark pointer-events-none cursor-not-allowed;
}
page
, page-size
, total-items
are the properties that the pagination taghelper uses to generate the paging links.
These are passed into the partial view from the controller.
public IActionResult Index(int page = 1, int pageSize = 5)
Here page and pageSize are passed in from the URL and the total items are calculated from the blog service.
public PostListViewModel GetPostsForFiles(int page=1, int pageSize=10)
{
var model = new PostListViewModel();
var posts = GetPageCache().Values.Select(GetListModel).ToList();
model.Posts = posts.OrderByDescending(x => x.PublishedDate).Skip((page - 1) * pageSize).Take(pageSize).ToList();
model.TotalItems = posts.Count();
model.PageSize = pageSize;
model.Page = page;
return model;
}
Here we simply get the posts from the cache, order them by date and then skip and take the correct number of posts for the page.
This was a simple addition to the site but it makes it much more usable. The HTMX integration makes the site feel more responsive while not adding more JavaScript to the site.