Decorator pattern in Pagination UI component
- Posted in:
- Web dev
About a year a go I released nuget package for creating simple pager HTML, specifically designed to work nicely with bootstrap, since, well, the whole damn world is using that CSS framework. Until next better framework arrives ...
It's a simple code, but to "calculate" which pages have to displayed in the pager (e.g.: 1 ... 2 3 [4] 5 6 ... 50), there's some logic behind it, so worth of packaging it into a nuget, IMHO.
There are 3 packages released, depending how high or low somebody wants to go with abstraction
- JA.Pagination - no dependency on any framework, API is just one Render() method with returns a string. Suitable for Nancy framework and similar ...
- JA.Pagination.MVC5 - extension method for MVC 5 HTML helper
- JA.Pagination.MVC6 - extension method for MVC Core (MVC 6, or now called v1 and v2)
Usage from MVC:
@Html.RenderPager(Model.CurrentPage, Model.TotalPages)
But, there's one more thing worth mentioning here - usage of Decorator design pattern. If you're just learning GoF Design Patterns and looking for a real world example, this could be useful!
Pager consists of several elements, like list item, link, content, etc. If you take a look at HTML code:
you’ll notice how text content, for example page “2” is inside <a> tag, which is inside <li> tag, which is inside <ul> tag! So we can say text “2” is decorated with link, list item and unordered list elements. That can be modelled nicely with code:
each of those classes inherit from interface:
meaning, each items needs to know how to render itself! But to get “decoration” pattern working, trick is to insert another IRenderable into constructor, and that will make one IRenderable decorator of another IRenderable:
Here LinkDecorator doesn’t really care what it is decorating with <a> and </a>, it just needs to invoke that _inner.Render()!
When some top level object calls Render() method of an object, that method will call inner.Render(), that then calls its own inner.Render(), and so on, depending how many decorators we definded.
Simple, right?
Check full source code at Github.