1

I am working on developing a dynamic DataTable in which the data source is dynamically generated with [n] columns, where the data source may contain 4 columns or 6 columns as an example. As per this post on the DataTables forum (How to Render Columns from a dynamic data source) it is possible to define and build a variable of a column defintions, and pass this to the initialisation.

Based on this I have created the following code that works well for the given purpose and renders the columns dynaically based on the data source.

HTML:

 <div class="data-table">
        <table id="dataTable" class="table table-striped table-bordered" style="width:100%;"></table>
    </div>

Script:

 <script>
    var dataToSend = {};
    var dataTable;

    dataToSend = {
        "regionId": @Model.RegionId
    }

    // Get Column Defintions
    var dtColumns = @Html.Raw(Json.`enter code here`Serialize(listOfDefintions));

    // DataTable
    $(function () {
        dataTable = {
            dt: null,

            init: function () {
                dt = $("#dataTable").DataTable({
                    ajax: {
                        type: "GET",
                        url: "@Url.Action("GetDataForGrid", "Contact")",
                        data: function () {
                            return dataToSend;
                        },
                        datatype: "json",
                        dataSrc: ""
                    },
                    columns: dtColumns,
                    lengthMenu: [[10, 25, 50, 100], [10, 25, 50, 100]],
                });
            },
            refresh: function () {
                dt.ajax.reload();
            }
        }

        dataTable.init();
    });

</script>

The above code renders the following DataTable, based on the data source which can be seen below.

DataSource: Data Source

Rendered Table: DataTable

My question regards the empty final column of the table, in which I need to render a button. I would have normally written something along the lines of the code below, if I had been wanting to render a table with known column values, in which I would use the DataTable property column.Render. As you can see below, using the data property of the column, I can use create a function to render a button, which can be used to quick navigate to the Contact/Edit page passing the "id" as a Url route value, meaning that it is possible to edit the specific details of the choosen contact.

 <script>
    var dataToSend = {};
    var contactDataTable;

    dataToSend = {
       "regionId": @Model.RegionId
    };

    $(function () {
        contactDataTable = {
            dt: null,

            init: function () {
                dt = $('#contact-data-table').DataTable({
                    ajax: {
                        type: "GET",
                        url: "@Url.Action("GetDataForGrid", "Contact")",
                        data: function () {
                            return dataToSend;
                        },
                        datatype: "json",
                        dataSrc: ""
                    },
                    columns: [
                        {
                            "title": "Forename",
                            "data": "forename",
                            "searchable": true,
                        },
                        {
                            "title": "Surname",
                            "data": "surname",
                            "searchable": true,
                        },
                        {
                            "title": "Email",
                            "data": "email",
                            "searchable": true
                        },
                        {
                            "Status":
                            "status":
                            "searchable":
                        },
                        {
                            "title": "Role",
                            "data": "roleName",
                            "searchable": true
                        },
                        {
                            "title": "",
                            "data": "id",
                            "searchable": false,
                            "sortable": false,
                            "render": function (data, type, full, meta) {
                                var buffer = '<a href="@Url.Action("Edit","Contact")/' + data  + '" class="btn btn-sm btn-primary js-action"><i class="far fa-edit"></i></a>&nbsp;'

                                buffer += '<a href="@Url.Action("Delete", "Contact")/' + data + '" class="btn btn-sm btn-danger js-action"><i class="far fa-trash-alt"></i></a>';

                                return buffer;
                            }
                        }
                    ],
                    columnDefs: [
                        { "width": "15%", "targets": 0 },
                        { "width": "15%", "targets": 1 },
                        { "width": "20%", "targets": 2 },
                        { "width": "15%", "targets": 3 },
                        { "width": "15%", "targets": 4 },
                        { "width": "20%", "targets": 5 },
                    ],
                    lengthMenu: [[10, 25, 50, 100], [10, 25, 50, 100]],
                });
            },
            refresh: function () {
                dt.ajax.reload();
            }
        }
</script>

How can I achieve the same principle of rendering a button in my table if I am defining and building my column defintion variable before passing this to my DataTable intialization?

Any help would be great.

5
  • Sorry, I don't understand... You seem to be heading in a good direction, it should be possible to use the data-variable to construct a URL that passes the id - so where's the problem? Commented Oct 21, 2021 at 11:45
  • Suggestion: Instead of using dataSrc: "", use a function: dataSrc: function ( json ) { ... }. You can see an example here. This allows you to iterate over your source JSON data, and add a new object to each row - where the object is a string containing the HTML for the button you want to build. This is the equivalent to the logic you wanted to use in your column renderer. Commented Oct 21, 2021 at 13:19
  • @MBaas - In the example provided I was looking to render a button in the final column of the table, in which I was having difficulties acutally rendering the HTML element. In my various iterations to solve this problem, I was either able to render a button but not access the data property of the column, which in this case is the Id, and visa versa. Commented Oct 21, 2021 at 13:52
  • 2
    I have been able to resolve the problem in the meanwhile, which i will happily post if desired. I can problally look to resolve the issue as andrewJames suggests, however I found that simply setting the Data property of the final column to null, and defaultContent to render a simple button worked well. I then developed a on click event which obtained the data for the current row, in which I could access the Id property to use within the construction of my URL. There is mostly likely a better approach, in which case I will look to implement. Commented Oct 21, 2021 at 13:58
  • 2
    That's a good, straightforward solution. You are welcome to answer your own question - you can also accept it, if you want. That will help future visitors to the question. Commented Oct 21, 2021 at 14:06

1 Answer 1

3

A simple solution to the given problem is to use the Column.defaultContent property and a custom onClick event that can be used to construct the relevant URL required.

In the example below, I've modified my dtColumns array as seen in the provided image, so that the relevant object contain a definition for defaultContent, set to a string that will render a simple button. For the defaultContent to be used by the DataTable, you must set the Data property to null.

DataTable - Data Source

var myColumnDefs = [
        { title: "Forename", data: "forename", width: "15%"},
        { title: "Surname", data: "surname", width: "15%"},
        { title: "Email", data: "email", width: "20%"},
        { title: "Status", data: "status", width: "15%"},
        { title: "Role", data: "roleName", width: "15%"},
        { title: "", data: "(string)null", width: "20%", searchable: false, sortable: false, defaultContent: "<a id='btnEdit' class='btn btn-sm btn-primary js-action'><i class='fas fa-edit'></i></a>"}
    ]

In doing so, a table such as the one below is rendered:

Rendered DataTable

The modified code really only includes extra functions to handle the onClick event of the buttons. In this case, I can obtain the data of the loaded record by using $("#dataTable").DataTable().row((selectedRow).parents("tr")).data(), in which the id property can be accessed. Using this Id value I was then able to construct the desired URL which happens to be passed into a function that renders a Bootstrap Modal.

    <script>
    var dataToSend = {};
    var dataTable;

    // Set Data To Send
    dataToSend = {
        "regionId": "@Model.RegionId"
    }

    // Get Column Defintions
    var dtColumns = @Html.Raw(Json.Serialize(listOfDefintions));

    // DataTable
    $(function () {
        dataTable = {
            dt: null,

            init: function () {
                dt = $("#dataTable").DataTable({
                    ajax: {
                        type: "GET",
                        url: "@Url.Action("GetDataForGrid", "Contact")",
                        data: function () {
                            return dataToSend;
                        },
                        datatype: "json",
                        dataSrc: ""
                    },
                    columns: dtColumns,
                    lengthMenu: [[10, 25, 50, 100], [10, 25, 50, 100]],
                });
            },
            refresh: function () {
                dt.ajax.reload();
            }
        }

        dynaGridDataTable.init();


        // DataTable Buttons
        $("#dataTable").on("click", ".js-action", function (event) {
            var btnId = $(this).attr("id");
            var recordId = getRecordId($(this));

            if (btnId !== undefined && btnId == "btnEdit") {
                // Create Edit URL
                var href = '@Url.Action("Popup", "DynaGrid")[email protected]&[email protected]&id=' + recordId + '';
                
                renderModalForDataTableButton(href);
            } else if (btnId !== undefined && btnId == "btnDelete") {
                // Code 
                
            } else {
                alert("Something Went Wrong - Unable To Redirect");
            }
        });

        // Get Record Id Of Current Row
        function getRecordId(selectedRow) {
            var data = $("#dataTable").DataTable().row((selectedRow).parents("tr")).data();
            return data.id;
        }

        function renderModalForDataTableButton(href) {
            $.get(href, function (data) {
                $('#myModalContent').html(data);
                $('#myModal').modal('show');
            });
        }
    });
</script>
Sign up to request clarification or add additional context in comments.

1 Comment

Please prefer to type up code, logs, etc instead of screenshotting. This makes it more readable for many users AND indexable by search engine bots.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.