Hello developers, welcome to my first ever article. I feel privileged and happy to help and teach you this. In this article we will try to look at Jquery DataTables with Asp.Net Core Server Side Processing. The primary goal of this article is to make multiple column server-side sorting and searching along with pagination and excel export to be dynamic and easy to implement. There is a plethora of articles available on the same topic. This article is an attempt to explain in my own words with my own implementation using the Nuget Package that I developed.
Background

This tutorial contains example for both Ajax Get and Ajax Post Server-Side Configuration.
A look at Asp.Net Core Server Side
- public class Demo
- {
- [SearchableInt]
- [Sortable]
- public int Id { get; set; }
- [SearchableString]
- [Sortable(Default = true)]
- public string Name { get; set; }
- [SearchableString]
- [Sortable]
- public string Position { get; set; }
- [Display(Name = "Office")]
- [SearchableString(EntityProperty = "Office")]
- [Sortable(EntityProperty = "Office")]
- public string Offices { get; set; }
- [NestedSearchable]
- [NestedSortable]
- public DemoNestedLevelOne DemoNestedLevelOne { get; set; }
- }
- public class DemoNestedLevelOne
- {
- [SearchableShort]
- [Sortable]
- public short? Experience { get; set; }
- [DisplayName("Extn")]
- [SearchableInt(EntityProperty = "Extn")]
- [Sortable(EntityProperty = "Extn")]
- public int? Extension { get; set; }
- [NestedSearchable(ParentEntityProperty = "DemoNestedLevelTwo")]
- [NestedSortable(ParentEntityProperty = "DemoNestedLevelTwo")]
- public DemoNestedLevelTwo DemoNestedLevelTwos { get; set; }
- }
- public class DemoNestedLevelTwo
- {
- [SearchableDateTime(EntityProperty = "StartDate")]
- [Sortable(EntityProperty = "StartDate")]
- [DisplayName("Start Date")]
- public DateTime? StartDates { get; set; }
- [SearchableLong]
- [Sortable]
- public long? Salary { get; set; }
- }
As shown in the above code, you can enable searching/sorting to the columns by adding [Searchable]/[Sortable] attributes to your model properties. [NestedSortable]/[NestedSearchable] attributes adds sorting/searching to complex model/properties.
[Sortable] adds the sorting functionality to the columns while [Sortable(Default = true)] will make a default initial sorting of your records.
- [Sortable]
- [Sortable(Default = true)]
- [NestedSortable]
[Searchable] adds the searching functionality to the columns. Searching has some flavors added to it based on the data type of the column to help build the search expression dynamically. I have created
- [Searchable]
- [SearchableString]
- [SearchableInt]
- [SearchableShort]
- [SearchableDecimal]
- [SearchableDouble]
- [SearchableDateTime]
- [SearchableLong]
- [NestedSearchable]
Column Names:
Using the Code
Note
I’m using Asp.Net Core 3.0
- I started with an empty solution and added the necessary Nuget Packages to get the demo up and running.

- Let’s begin with the server-side configuration and database setup. For jQuery DataTables to work with Asp.Net Core, we first need to call setup ConfigureServices in the Startup.cs. I have also added AutoMapper to take care of mappings and AddSession which I’ll explain later.
For AutoMapper to work add the following Nuget Packages:
- AutoMapper
- Extensions.Microsoft.DependencyInjection
For Asp.Net Core 3.0:
If you are using System.Text.Json, then setup your ConfigureServices as below:If you are using Json.Net, then setup your ConfigureServices as below:- services.AddControllersWithViews()
- .AddJsonOptions(options =>
- {
- options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
- options.JsonSerializerOptions.PropertyNamingPolicy = null;
- });
- services.AddSession();
- services.AddAutoMapper(typeof(Startup));
For Asp.Net Core 2.x, setup your ConfigureServices as below:- services.AddControllersWithViews()
- .AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
- services.AddSession();
- services.AddAutoMapper(typeof(Startup));
- services.AddMvc()
- .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
- services.AddSession();
- services.AddAutoMapper(typeof(Startup));
- I’ll be using an InMemoryDatabase for this demo.
Note
If you already have a datatabase setup and you’re familiar with database implementation you can skip to step 8.
- // Use in-memory database for quick dev and testing
- services.AddDbContext<Fingers10DbContext>(
- options =>
- {
- options.UseInMemoryDatabase("fingers10db");
- });
- The Fingers10DbContext class has a DemoEntityDbSet, which will be used to query the datatabase.
- public class Fingers10DbContext:DbContext
- {
- public Fingers10DbContext(DbContextOptions options)
- : base(options) { }
- public DbSet<DemoEntity> Demos { get; set; }
- }
- The DemoEntity class has the following fields.
Root Entity
Nested Level One Entity- public class DemoEntity
- {
- [Key]
- public int Id { get; set; }
- public string Name { get; set; }
- public string Position { get; set; }
- public string Office { get; set; }
- public DemoNestedLevelOneEntity DemoNestedLevelOne { get; set; }
- }
Nested Level Two Entity- public class DemoNestedLevelOneEntity
- {
- [Key]
- public int Id { get; set; }
- public short? Experience { get; set; }
- public int? Extn { get; set; }
- public DemoNestedLevelTwoEntity DemoNestedLevelTwo { get; set; }
- }
- public class DemoNestedLevelTwoEntity
- {
- [Key]
- public int Id { get; set; }
- public DateTime? StartDate { get; set; }
- public long? Salary { get; set; }
- }
- Now let’s add a static SeedData class to seed the data and call it from the Program.cs.
- public static class SeedData
- {
- public static async Task InitializeAsync(IServiceProvider services)
- {
- await AddTestData(
- services.GetRequiredService<Fingers10DbContext>());
- }
- public static async Task AddTestData(Fingers10DbContext context)
- {
- if(context.Demos.Any())
- {
- // Already has data
- return;
- }
- var testData = new List<DemoEntity>()
- {
- new DemoEntity {
- Name = "Airi Satou",
- Position = "Accountant",
- Office = "Tokyo",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = null,
- Extn = null,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = null,
- Salary = null
- }
- }
- },
- new DemoEntity {
- Name = "Angelica Ramos",
- Position = "Chief Executive Officer (CEO)",
- Office = "London",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = 1,
- Extn = 5797,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = new DateTime(2009,10,09),
- Salary = 1200000
- }
- }
- },
- new DemoEntity {
- Name = "Ashton Cox",
- Position = "Junior Technical Author",
- Office = "San Francisco",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = 2,
- Extn = 1562,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = new DateTime(2009,01,12),
- Salary = 86000
- }
- }
- },
- new DemoEntity {
- Name = "Bradley Greer",
- Position = "Software Engineer",
- Office = "London",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = 3,
- Extn = 2558,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = new DateTime(2012,10,13),
- Salary = 132000
- }
- }
- },
- new DemoEntity {
- Name = "Brenden Wagner",
- Position = "Software Engineer",
- Office = "San Francisco",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = 4,
- Extn = 1314,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = new DateTime(2011,06,07),
- Salary = 206850
- }
- }
- },
- new DemoEntity {
- Name = "Brielle Williamson",
- Position = "Integration Specialist",
- Office = "New York",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = 5,
- Extn = 4804,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = new DateTime(2012,12,02),
- Salary = 372000
- }
- }
- },
- new DemoEntity {
- Name = "Bruno Nash",
- Position = "Software Engineer",
- Office = "London",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = 6,
- Extn = 6222,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = new DateTime(2011,05,03),
- Salary = 163500
- }
- }
- },
- new DemoEntity {
- Name = "Caesar Vance",
- Position = "Pre-Sales Support",
- Office = "New York",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = 7,
- Extn = 8330,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = new DateTime(2011,12,12),
- Salary = 106450
- }
- }
- },
- new DemoEntity {
- Name = "Cara Stevens",
- Position = "Sales Assistant",
- Office = "New York",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = 8,
- Extn = 3990,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = new DateTime(2011,12,06),
- Salary = 145600
- }
- }
- },
- new DemoEntity {
- Name = "Cedric Kelly",
- Position = "Senior Javascript Developer",
- Office = "Edinburgh",
- DemoNestedLevelOne = new DemoNestedLevelOneEntity
- {
- Experience = 9,
- Extn = 6224,
- DemoNestedLevelTwo = new DemoNestedLevelTwoEntity
- {
- StartDate = new DateTime(2012,03,29),
- Salary = 433060
- }
- }
- }
- };
- context.Demos.AddRange(testData);
- await context.SaveChangesAsync();
- }
- }
- Inside the Program.cs, let’s call InitializeDatabase method from the Main method to seed data into the database.
- public class Program
- {
- public static void Main(string[] args)
- {
- var host = CreateWebHostBuilder(args).Build();
- InitializeDatabase(host);
- host.Run();
- }
- public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
- .UseStartup<Startup>();
- private static void InitializeDatabase(IWebHost host)
- {
- using (var scope = host.Services.CreateScope())
- {
- var services = scope.ServiceProvider;
- try
- {
- SeedData.InitializeAsync(services).Wait();
- }
- catch (Exception ex)
- {
- var logger = services.GetRequiredService<ILogger<Program>>();
- logger.LogError(ex, "An error occurred seeding the database.");
- }
- }
- }
- }
- Here comes the DataTables part. First install the required client-side libraries for Jquery DataTables to work. I’m using LibMan to install JQuery DataTables along with Bootstrap, jQuery and js. And don’t forget to add reference to the files in your HTML.

- @addTagHelper *, JqueryDataTables.ServerSide.AspNetCoreWeb
-
Now add <jquery-datatables> in your html as shown below.
- <jquery-datatables id="fingers10"
- class="table table-sm table-dark table-bordered table-hover"
- model="@Model"
- thead-class="text-center"
- enable-searching="true"
- search-row-th-class="p-0"
- search-input-class="form-control form-control-sm"
- search-input-style="width:100%"
- search-input-placeholder-prefix="Search">
- </jquery-datatables>
* id - to add id to the html table* class - to apply the given css class to the html table* model - view model with properties to generate columns for html table* thead-class - to apply the given css class to the `<thead>` in html table* enable-searching - `true` to add search inputs to the `<thead>` and `false` to remove search inputs from the `<thead>`* search-row-th-class - to apply the given css class to the search inputs row of the `<thead>` in the html table* search-input-class - to apply the given css class to the search input controls added in each column inside `<thead>`* search-input-style - to apply the given css styles to the search input controls added in each column inside `<thead>`* search-input-placeholder-prefix - to apply your placeholder text as prefix in search input controls in each column inside `<thead>` - Now initialize DataTable as shown below, make sure to add serverSide: true and orderCellsTop: true; serverSide informs DataTable that the data will be coming from the server from the URL mentioned in ajax post and orderCellsTop places the sorting icons to the first row inside the thead. You can also pass additional parameters to the server using AdditionalValues property as string and cast back to required type in server and use those for any manipulations.
Ajax POST Configuration
Ajax GET Configuration- var table = $('#fingers10').DataTable({
- language: {
- processing: "Loading Data...",
- zeroRecords: "No matching records found"
- },
- processing: true,
- serverSide: true,
- orderCellsTop: true,
- autoWidth: true,
- deferRender: true,
- lengthMenu: [5, 10, 15, 20],
- dom: '<"row"<"col-sm-12 col-md-6"B><"col-sm-12 col-md-6 text-right"l>><"row"<"col-sm-12"tr>><"row"<"col-sm-12 col-md-5"i><"col-sm-12 col-md-7"p>>',
- buttons: [
- {
- text: 'Export to Excel',
- className: 'btn btn-sm btn-dark',
- action: function (e, dt, node, config) {
- window.location.href = "/Home/GetExcel";
- },
- init: function (api, node, config) {
- $(node).removeClass('dt-button');
- }
- }
- ],
- ajax: {
- type: "POST",
- url: '/Home/LoadTable/',
- contentType: "application/json; charset=utf-8",
- async: true,
- headers: {
- "XSRF-TOKEN": document.querySelector('[name="__RequestVerificationToken"]').value
- },
- data: function (data) {
- let additionalValues = [];
- additionalValues[0] = "Additional Parameters 1";
- additionalValues[1] = "Additional Parameters 2";
- data.AdditionalValues = additionalValues;
- return JSON.stringify(data);
- }
- },
- columns: [
- ...
- ]
- });
For AJAX GET configuration, simply change the `ajax` and `buttons` options as follows,
- buttons: [
- {
- text: 'Export to Excel',
- className: 'btn btn-sm btn-dark',
- action: function (e, dt, node, config) {
- var data = table.ajax.params();
- var x = JSON.stringify(data, null, 4);
- window.location.href = "/Home/GetExcel?" + $.param(data);
- },
- init: function (api, node, config) {
- $(node).removeClass('dt-button');
- }
- }
- ],
- ajax: {
- url: '/Home/LoadTable/',
- data: function (data) {
- return $.extend({}, data, {
- "additionalValues[0]": "Additional Parameters 1",
- "additionalValues[1]": "Additional Parameters 2"
- });
- }
- }
- columns: [
- {
- data: "Id",
- name: "eq",
- visible: false,
- searchable: false
- },
- {
- data: "Name",
- name: "co"
- },
- {
- data: "Position",
- name: "co"
- },
- {
- data: "Offices",
- name: "eq"
- },
- {
- data: "DemoNestedLevelOne.Experience",
- name: "eq"
- },
- {
- data: "DemoNestedLevelOne.Extension",
- name: "eq"
- },
- {
- data: "DemoNestedLevelOne.DemoNestedLevelTwos.StartDates",
- render: function (data, type, row) {
- if (data)
- return window.moment(data).format("DD/MM/YYYY");
- else
- return null;
- },
- name: "gt"
- },
- {
- data: "DemoNestedLevelOne.DemoNestedLevelTwos.Salary",
- name: "lte"
- }
- ]
- The data property must match the name of the property in the DemoModel.cs and this is case sensitive. Title is the readable form of your Model property describing the column.
- I’m using the name property to send the type of search that I need to perform in each column as I’m not able to find any other properties with DataTable Columns.

Note
If you’re not using name property, then this will default to eq search operation.
- Before we move to server-side implementation, add the following script to perform search on press of enter key. Make sure to replace id with your table id.
- table.columns().every(function (index) {
- $('#fingers10 thead tr:last th:eq(' + index + ') input')
- .on('keyup',
- function (e) {
- if (e.keyCode === 13) {
- table.column($(this).parent().index() + ':visible').search(this.value).draw();
- }
- });
- });
- If you need to perform search on press of Tab Key instead of Enter Key, ignore the above script and add the below script.
- $('#fingers10 thead tr:last th:eq(' + index + ') input')
- .on('blur',
- function () {
- table.column($(this).parent().index() + ':visible').search(this.value).draw();
- });
- Now for this to work on the server side, install the Nuget Package – JqueryDataTables.ServerSide.AspNetCoreWeb which I have created to do all the heavy lifting for you.
- Now add JqueryDataTablesParameters class as a parameter to your action method as shown below. And return the data back to DataTable as a JsonResult using JqueryDataTablesResult<T> class as shown below.
Note
Return data is of IEnumerable<T> Type.
AJAX POST Configuration
- [HttpPost]
- public async Task<IActionResult> LoadTable([FromBody]JqueryDataTablesParameters param)
- {
- try
- {
- // `param` is stored in session to be used for excel export. This is required only for AJAX POST.
- // Below session storage line can be removed if you're not using excel export functionality.
- HttpContext.Session.SetString(nameof(JqueryDataTablesParameters), JsonSerializer.Serialize(param));
- var results = await _demoService.GetDataAsync(param);
- return new JsonResult(new JqueryDataTablesResult<Demo> {
- Draw = param.Draw,
- Data = results.Items,
- RecordsFiltered = results.TotalSize,
- RecordsTotal = results.TotalSize
- });
- } catch(Exception e)
- {
- Console.Write(e.Message);
- return new JsonResult(new { error = "Internal Server Error" });
- }
- }
Note
Serialize and save the param model in Session to be used for Excel Export. This needs to be done for Post Request only.
- public async Task<IActionResult> LoadTable([ModelBinder(typeof(JqueryDataTablesBinder))] JqueryDataTablesParameters param)
- {
- try
- {
- var results = await _demoService.GetDataAsync(param);
- return new JsonResult(new JqueryDataTablesResult<Demo> {
- Draw = param.Draw,
- Data = results.Items,
- RecordsFiltered = results.TotalSize,
- RecordsTotal = results.TotalSize
- });
- } catch(Exception e)
- {
- Console.Write(e.Message);
- return new JsonResult(new { error = "Internal Server Error" });
- }
- }
- public class DefaultDemoService:IDemoService
- {
- private readonly Fingers10DbContext _context;
- private readonly IConfigurationProvider _mappingConfiguration;
- public DefaultDemoService(Fingers10DbContext context,IConfigurationProvider mappingConfiguration)
- {
- _context = context;
- _mappingConfiguration = mappingConfiguration;
- }
- public async Task<JqueryDataTablesPagedResults<Demo>> GetDataAsync(JqueryDataTablesParameters table)
- {
- IQueryable<DemoEntity> query = _context.Demos
- .AsNoTracking()
- .Include(x => x.DemoNestedLevelOne)
- .ThenInclude(y => y.DemoNestedLevelTwo);
- query = SearchOptionsProcessor<Demo,DemoEntity>.Apply(query,table.Columns);
- query = SortOptionsProcessor<Demo,DemoEntity>.Apply(query,table);
- var size = await query.CountAsync();
- var items = await query
- .AsNoTracking()
- .Skip((table.Start / table.Length) * table.Length)
- .Take(table.Length)
- .ProjectTo<Demo>(_mappingConfiguration)
- .ToArrayAsync();
- return new JqueryDataTablesPagedResults<Demo> {
- Items = items,
- TotalSize = size
- };
- }
- }
- public class MappingProfile : Profile
- {
- public MappingProfile()
- {
- CreateMap<DemoEntity, Demo>()
- .ForMember(dest => dest.Offices, opts => opts.MapFrom(src => src.Office));
- CreateMap<DemoNestedLevelOneEntity, DemoNestedLevelOne>()
- .ForMember(dest => dest.Extension, opts => opts.MapFrom(src => src.Extn))
- .ForMember(dest => dest.DemoNestedLevelTwos, opts => opts.MapFrom(src => src.DemoNestedLevelTwo));
- CreateMap<DemoNestedLevelTwoEntity, DemoNestedLevelTwo>()
- .ForMember(dest => dest.StartDates, opts => opts.MapFrom(src => src.StartDate));
- CreateMap<Demo, DemoExcel>();
- }
- }
-
Note
If you’re having Services in a separate project, then create an instance of SearchOptionsProcessor and SortOptionsProcessor inside the controller action method and pass it as parameters to your service calls.
- That’s it -- now your DataTable works with server-side dynamic multiple column searching and sorting with pagination.
Now for exporting the filtered and sorted data as an excel file, add GetExcel action method in your controller as shown below. Return the data as JqueryDataTablesExcelResult<T> by passing filtered/ordered data, excel sheet name and excel file name. My Nuget package will take care of converting your data as excel file and return it back to browser.
AJAX POST Configuration
- public async Task<IActionResult> GetExcel()
- {
- var param = HttpContext.Session.GetString(nameof(JqueryDataTablesParameters));
- var results = await _demoService.GetDataAsync(JsonSerializer.Deserialize<JqueryDataTablesParameters>(param));
- return new JqueryDataTablesExcelResult<DemoExcel>(_mapper.Map<List<DemoExcel>>(results.Items), "Demo Sheet Name", "Fingers10");
- }
Note - public async Task<IActionResult> GetExcel([ModelBinder(typeof(JqueryDataTablesBinder))] JqueryDataTablesParameters param)
- {
- var results = await _demoService.GetDataAsync(param);
- return new JqueryDataTablesExcelResult<DemoExcel>(_mapper.Map<List<DemoExcel>>(results.Items), "Demo Sheet Name", "Fingers10");
- }
Get the params stored in Session as shown in step 17 and Deserialize and use it to get the filtered/ordered data. This needs to be done for Post Request only. If you want all the results in excel export without pagination, then please write a separate service method to retrive data without using Take() and Skip().
AJAX GET Configuration
Point of Interest
Thanks for reading.
- Full updated documentation can be found here in my GitHub Page - JqueryDataTablesAspNetCoreServerSide
- Download sample demo code for this article from my GitHub Repo - JqueryDataTablesServerSideDemo
Add a star to my repo if this saved you effort and time.
AbdulkarimPosted Sep 2, 2020, 9:08 PM
Thank you for the article. it is very useful. I am facing a problem. I have one column with a boolean value. when try to search. I am getting error: "No coercion operator is defined between types 'System.String' and 'System.Boolean'." when calling Apply for SearchOptionsProcessor. Is there a way to perform the boolean search? thanks
Abdul RahmanPosted May 21, 2020, 7:25 PM
@Ivan Climov, the sequence is not broken. All the points listed are in order. May be this could be a formatting issue.
Ivan ClimovPosted May 20, 2020, 2:37 PM
You have broken the sequence of paragraphs.Example: ..- 9 - ?? - 11 -... ..- 15 - ?? - 17 -...
neha khandelwalPosted Apr 29, 2020, 1:22 AM
I cant see my table headers on the table, wht can be the reason, please help.
ramazan kızılkayaPosted Jan 21, 2020, 3:28 AM
Hi, i couldn't implement the project since i am a junior developer. I havew some namespace problems. Would you mind create and share a simple project for us? Regards.
NestorleonePosted Jan 9, 2020, 8:56 AM
Excellent!! I was able to run the demo flawless, but, When I inserted this library copying the methods here I get "NullReferenceException: Object reference not set to an instance of an object. JqueryDataTables.ServerSide.AspNetCoreWeb.TagHelpers.JqueryDataTablesTagHelper.GetColumnsFromModel(Type parentClass)+MoveNext()" Any ideas why ?
Bernard BoakyePosted Dec 18, 2019, 6:34 PM
Hi, is there a way to support filtering outside the fields in the grid, say date range of when the records were created?
Maurice AboagyePosted Dec 15, 2019, 4:47 PM
Hello Abdul, I followed your link to download your update on https://github.com/fingers10/JqueryDataTablesServerSideDemo. It answers my question exactly. Thanx very much
Hunain DurraniPosted Oct 28, 2019, 6:48 AM
Hi Abdul Rahman, Great job its really a nice article. I am using jquery datatable in my project but the problem is i dont want to show some of my model fields in my grid how can i achieve this. i tried using the visible property of grid column but did't work.
Maurice AboagyePosted Oct 10, 2019, 10:27 AM
Great Article . Pls can you extend the Article to do CRUD (Create, Read, Update, delete) Operations with Microsoft SQl Server?
alex zPosted Aug 31, 2019, 3:43 PM
Great article and of course interesting. If i want to add country from another table to the search column, how can I add a button or a modal witch if record is not found to ask for the creating a new record and open the create view for country?
Marc VillellaPosted Jul 30, 2019, 6:49 AM
Great article, Abdul! Is there a way to move to a signle search above the table instead of one per column?
Abdul RahmanPosted Jul 28, 2019, 9:24 AM
Remove the buttons:[] from jquery datatables initialization script.
no namePosted Jul 28, 2019, 8:25 AM
How do I hide Export to Excel button
Fungai MashozheraPosted Jul 23, 2019, 2:56 AM
I like this. How do i add action buttons to the rows, for example buttons for editing and details.
Amit MohantyPosted Jun 27, 2019, 2:08 AM
Nice Article !!!