ASP.NET8 using DataTables.net – Part8 – Select rows

Mark PelfMark Pelf
7 min read

ASP.NET8 using DataTables.net – Part8 – Select rows

A practical guide to using jQuery DataTables.net component in Asp.Net 8 MVC application.

Abstract: A practical guide to building an Asp.Net 8 MVC application that uses jQuery component DataTables.net. This is a continuation of article Part7.

1 ASP.NET8 using jQuery DataTables.net

I was evaluating the jQuery DataTables.net component [1] for usage in ASP.NET8 projects and created several prototype (proof-of-concept) applications that are presented in these articles.

1.1 Articles in this series

Articles in this series are:

  • ASP.NET8 using DataTables.net – Part1 – Foundation
  • ASP.NET8 using DataTables.net – Part2 – Action buttons
  • ASP.NET8 using DataTables.net – Part3 – State saving
  • ASP.NET8 using DataTables.net – Part4 – Multilingual
  • ASP.NET8 using DataTables.net – Part5 – Passing additional parameters in AJAX
  • ASP.NET8 using DataTables.net – Part6 – Returning additional parameters in AJAX
  • ASP.NET8 using DataTables.net – Part7 – Buttons regular
  • ASP.NET8 using DataTables.net – Part8 – Select rows
  • ASP.NET8 using DataTables.net – Part9 – Advanced Filters

2 Final result

The goal of this article is to create a proof-of-concept application that demos DataTables.net component selection of rows in the table. Let us present the result of this article.

The point is, the component DataTables.net lets you select rows in the table and pass selection information for processing to some other action.

We are here showing general purpose buttons Select All/Deselect All.

Then we show 2 actions with selected rows, the first is just Showing selected rows IDs, and the second is passing the list of selected rows IDs to some action for processing.

3 Downloading DataTables component

Site [1] describes several ways to get the component, including CDN and NuGet packages. Not all worked well enough for me, so I found the best for me was to download it directly from the site and deploy it directly in the project.

You can look into datatables.js header to see what version you have on your system.

//datatables.js

/*
 * This combined file was created by the DataTables downloader builder:
 *   https://datatables.net/download
 *
 * To rebuild or modify this file with the latest versions of the included
 * software please visit:
 *   https://datatables.net/download/#bs5/jszip-3.10.1/pdfmake-0.2.7/dt-2.0.8/b-3.0.2/b-colvis-3.0.2/b-html5-3.0.2/b-print-3.0.2/sl-2.0.3/sr-1.4.1
 *
 * Included libraries:
 *   JSZip 3.10.1, pdfmake 0.2.7, DataTables 2.0.8, Buttons 3.0.2, Column visibility 3.0.2, HTML5 export 3.0.2, Print view 3.0.2, Select 2.0.3, StateRestore 1.4.1
 */

4 JavaScript Utils

For this example, we need some JavaScript helper functions. Here they are.

//util1.js

/**
* sends a request to the specified url from a form. this will change the window location.
* @param {string} path the path to send the post request to
* @param {object} params the parameters to add to the url
* @param {string} [method=post] the method to use on the form
*
* Warning: This solution is limited and does not handle arrays or nested objects inside of a form.
*/

function postToUrl1(path, params, method = 'post') {

    // The rest of this code assumes you are not using a library.
    // It can be made less verbose if you use one.
    const form = document.createElement('form');
    form.method = method;
    form.action = path;

    for (const key in params) {
        if (params.hasOwnProperty(key)) {
            const hiddenField = document.createElement('input');
            hiddenField.type = 'hidden';
            hiddenField.name = key;
            hiddenField.value = params[key];

            form.appendChild(hiddenField);
        }
    }

    document.body.appendChild(form);
    form.submit();
}

//function is used when we need to extract a list of a given property
//extract values from an array of objects based on a specific key
function PluckUtil1(array, key) {
    return array.map(function (obj) {
        return obj[key];
    });
}

5 Client-side DataTables.net component

Here I will just show what the ASP.NET view using DataTables component looks like.

<!-- Employees.cshtml -->
<partial name="_LoadingDatatablesJsAndCss" />

@{
    <div class="text-center">
        <h3 class="display-4">Employees table</h3>
    </div>

    <!-- Here is our table HTML element defined. JavaScript library Datatables
    will do all the magic to turn it into interactive component -->
    <table id="EmployeesTable01" class="table table-striped table-bordered ">
    </table>
}

<script src="~/lib/JSUtil/util1.js" asp-append-version="true"></script>

<script>
    // Datatables script initialization=========================================
    // we used defer attribute on jQuery so it might not be available at this point
    // so we go for vanilla JS event

    document.addEventListener("DOMContentLoaded", InitializeDatatable);

    function InitializeDatatable() {
        let myTable = new DataTable("#EmployeesTable01", {
            //processing-Feature control the processing indicator.
            processing: true,
            //paging-Enable or disable table pagination.
            paging: true,
            //info-Feature control table information display field
            info: true,
            //ordering-Feature control ordering (sorting) abilities in DataTables.
            ordering: true,
            //searching-Feature control search (filtering) abilities
            searching: true,
            //search.return-Enable / disable DataTables' search on return.
            search: {
                return: true
            },
            //autoWidth-Feature control DataTables' smart column width handling.
            autoWidth: true,
            //lengthMenu-Change the options in the page length select list.
            lengthMenu: [10, 15, 25, 50, 100],
            //pageLength-Change the initial page length (number of rows per page)
            pageLength: 10,

            //order-Initial order (sort) to apply to the table.
            order: [[2, 'asc']],

            //serverSide-Feature control DataTables' server-side processing mode.
            serverSide: true,

            //Select extension
            select: {
                style: 'os',
                selector: 'td:first-child',
                headerCheckbox: 'select-page'
            },

            //Load data for the table's content from an Ajax source.
            ajax: {
                "url": "@Url.Action("EmployeesDT", "Home")",
                "type": "POST",
                "datatype": "json"
            },

            //Set column specific initialization properties
            columns: [
                //name-Set a descriptive name for a column
                //data-Set the data source for the column from the rows data object / array
                //title-Set the column title
                //orderable-Enable or disable ordering on this column
                //searchable-Enable or disable search on the data in this column
                //type-Set the column type - used for filtering and sorting string processing
                //visible-Enable or disable the display of this column.
                //width-Column width assignment.
                //render-Render (process) the data for use in the table.
                //className-Class to assign to each cell in the column.

                {   //0
                    name: 'selectCheckbox',
                    //data: 'selectCheckbox',
                    //title: "",
                    orderable: false,
                    //searchable: false,
                    //type: 'num',
                    //visible: true,
                    render: DataTable.render.select(),
                    width: "50px",
                },
                {   //1
                    name: 'id',
                    data: 'id',
                    title: "Employee Id",
                    orderable: false,
                    searchable: false,
                    type: 'num',
                    visible: true
                },
                {
                    //2
                    name: 'givenName',
                    data: "givenName",
                    title: "Given Name",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true
                },
                {
                    //3
                    name: 'familyName',
                    data: "familyName",
                    title: "Family Name",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true
                },
                {
                    //4
                    name: 'town',
                    data: "town",
                    title: "Town",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true
                },
                {
                    //5
                    name: 'country',
                    data: "country",
                    title: "Country",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true,
                    width: "150px",
                    className: 'text-center '
                },
                {
                    //6
                    name: 'email',
                    data: "email",
                    title: "Email",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true
                },
                {
                    //7
                    name: 'phoneNo',
                    data: "phoneNo",
                    title: "Phone Number",
                    orderable: false,
                    searchable: true,
                    type: 'string',
                    visible: true
                }
            ],
            layout: {
                top1Start: {
                    buttons:
                        [
                            'selectNone',
                            'selectAll',
                            {
                                extend: 'selected',
                                text: 'Show selected data',
                                action: function () {
                                    let myRows = myTable.rows({ selected: true });
                                    let data = myRows.data();
                                    let ids = PluckUtil1(data, 'id');
                                    let idsString = ids.toArray().join(',');

                                    alert('Selected:' + idsString);
                                }
                            },
                            {
                                text: 'Deselect all2',
                                action: function () {
                                    let myRows = myTable.rows({ selected: true });
                                    myRows.deselect();
                                }
                            },
                            {
                                extend: 'selected',
                                text: 'Action with selected data',
                                action: function () {
                                    let myRows = myTable.rows({ selected: true });
                                    let data = myRows.data();
                                    let ids = PluckUtil1(data, 'id');
                                    let idsString = ids.toArray().join(',');

                                    //let SelectedEmployeesUrl = "@Url.Action("SelectedEmployees", "Home")" +
                                    //    "?SelectedIds=" + idsString;
                                    //redirect to another page
                                    //window.location.replace(SelectedEmployeesUrl);

                                    postToUrl1("@Url.Action("SelectedEmployees", "Home")", { SelectedIds: idsString });
                                }
                            },
                        ]
                }
            }
        });
    }

</script>

Note the layout property we used to define all the buttons in this example.

More about these properties can be found in the manual at [1]. The application here is just a proof of concept for ASP.NET environment.

6 ASP.NET back-end processing

So, we are now at C#/.NET part, writing our ASP.NET code. Here is the part to receive and process the list of IDs.

//SelectedEmployeesVM.cs
namespace Example08.Models.Home
{
    public class SelectedEmployeesVM
    {
        //model
        public string? SelectedIds { get; set; } = null;
        //view model
        public List<string>? SelectedIdsList { get; set; } = null;
    }
}

//HomeController.cs
public IActionResult SelectedEmployees(SelectedEmployeesVM model)
{
    model.SelectedIds = model.SelectedIds?.Trim();
    if (model.SelectedIds != null)
    {
        string[] strings = model.SelectedIds.Split(',');
        model.SelectedIdsList = new List<string>(strings);
    }
    return View(model);
}

7 Conclusion

The full example code project can be downloaded at GitHub [99].

8 References

[1] https://datatables.net/

[99] https://github.com/MarkPelf/ASPNET8UsingDataTablesNet

0
Subscribe to my newsletter

Read articles from Mark Pelf directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mark Pelf
Mark Pelf

A Software Engineer from Belgrade, Serbia.