A bit of history
One of the most important things when we think of reporting is a table with plenty of features. Such as ordering, filtering, selecting and so on. Back in the good old days of webforms and Rapid Application Development we had a very good control called GridView. It was clunky and, thanks to its ViewState, the page was getting very heavy after some interactions. In case you are not familiar with what I said, I'm talking about times where a simple ordering would trigger a page refresh (PostBack) and the state of the page controls was kept in a hidden field (the ViewState).
Some time later we had the infamous ASP.NET AJAX, which allowed us to use webform controls without page refresh. Unfortunately, all it did was to send the whole ViewState through Ajax. Meaning: We didn’t see the PostBack anymore but it was still happening in the background. The Ajax way. However, the page was still heavy.
With ASP.NET MVC we gained more control over the HTML output but we had to say goodbye to the Gridview control. Instead, we must use HTML table which, in all fairness, does the job. However, in more advanced scenarios, we would have to go for external libraries. And I am going to show you how to use my favorite one - DataTables.
Let’s see below how to implement it in a simple ASP.NET MVC Core website. You can get the demo on GitHub.
The normal implementation is relatively simple. All you need is a data source and a View. However, my implementation has some extra things to consider since I am going for a more flexible scenario. The whole idea is to have the backend do most of the data work and leave the library with the formatting. And for that we will use:
- Data source – No matter which. Memory, SQL Server, Oracle. Your choice;
- Models and ViewModels – We need some specific objects to make our job easier;
- Attributes – Important if we want to control the columns in the DataTable;
- Service, Helpers – Used to transform the raw data into something we can use;
- Reflection – Because we want the implementation to be as dynamic as possible;
- The API – We will load the data via Ajax, so we need a small API to work with;
- A View – Because we need to show the DataTable at some point
If you need to implement a data table it means you have a data source of some sort. In this demo we are going to use in-memory data but it could easily come from any kind of database. Here it is:
As you can see the PersonRepository should return all people (read only) and return the total amount of people in the imaginary “People table”.
Models and ViewModels
Some of these objects should help with data binding, others to help with the data formatting. You can find all of them here but the most important are:
We will use it to help with the data binding coming from the UI. It contains all we need to filter and order our data.
Used to shape the Person data coming from the data source into exactly what we need for the UI. It uses some custom attributes to help shaping the data and also some static methods to help with ordering and filtering.
This is the DataTable itself.
Since I am generating the DataTable information on the backend I decided to create some custom attributes to help me with it. You can see them here but, for short, they are:
- Orderable – In case the property has this attribute it means we can order our data;
- Searchable – The property containing this attribute will be used in the search field;
- ShowOnDataTable – It allows the property to be shown in the UI. You can also use it to set the order it will appear and a custom column name.
Service and Helpers
The Service is just a small mock of a Service Layer but it could be anything depending on the architecture you are following in your project. The most important is to create a specific method which return values formatted for the DataTable, as you can see below:
- The method accepts an argument of type DataParameters, which contains the values coming from the UI control;
- The static methods of PersonTableViewModel are being used to filter and order the data;
- The return type is a tuple.
As for the Helpers I have 2 classes. The first one is the ExpressionBuilder (bad name, I know), which will help us to build the expression queries for filtering. I am using because since the query is handling the data in-memory. Another scenario where the ExpressionBuilder would be useful is when we are using Entity Framework as we would dynamically build the query before sending to the database.
The other helper is the DataTableHelper. It will prepare both header and content for the UI based on the custom attributes we have in each property of PersonTableViewModel.
As you could see I am using a little bit of reflection to get the properties and custom attributes. In this way we would be able to add and remove columns by simply editing the PersonTableViewModel without breaking the UI.
- processing – Enables the process indicator;
- serverSide – Enables server-side processing of data;
- ajax – Loads the data from an Ajax source. In our case a dedicated method in the HomeController.
There are 2 things we need to make it happen in order to make the DataTable look good. The first is to setup the table headers. We will achieve that by returning a List<string> values when we call the page. That is done by using the BuildDataTableHeader method we made in the DataTableHelper, as seen below:
The second is to return the content data. We will create a specific method for that and name it GetPeopleData:
The idea here is to load the data and pass it into the BuildDataTable method in order to make it compatible with the DataTable library. The library, then, will get the data we are returning and format it into the HTML table.
From the top of the View:
- @model List<string> – Since we need to load the table headers in the beginning, we are passing it in the first request.
- The @foreach loop – Not the best place to do this but we need to prepare the header and footer tags in order to use it in the DataTable
- <table> – A the simple HTML table with some styles and the header/footer we just created
Don’t forget that the data coming via Ajax should match our columns perfectly, thanks to the DataTable script and the preparation we made in the backend.
And here we have, ladies and gentleman. A nice table with search and ordering:
The demo may seem overly complex for such a small thing but it scales quite well. I am using it both in my website and in a project at work with zero problems so far. Of course, some tweaks will be necessary when adapting to your project but it should be a no brainer. And once you grasp the concept it’s very easy to replicate it.
Once again, you can get the source code here: https://github.com/davidsonsousa/DataTables-With-AspNetCore
Maybe I will create a NuGet out of it someday 😉