Unable to get columnDefs.render to work on columns coming from AJAX request

Unable to get columnDefs.render to work on columns coming from AJAX request

barenabarena Posts: 3Questions: 1Answers: 0

Brief background: I need to be able to create a DataTable with a set of columns that comes from a configuration elsewhere in the system. In order to dynamically create the DataTables table I have piggybacked the DataTable init on the return from the "get columns" AJAX request. Up to this point everything is working.

The problem occurs when I attempt to add display rendering. It is not applied. In fact, the rendering functions are never called leading me to believe that it is unable to locate them. I use the columnDefs parameter on DataTables init to attempt to apply the display formatting based on class. Below is a simplified use case:

HTML:

<table id="adjustmentRequests" class="stripe"></table>

Javascript:

$.ajax( {
    url: "getDisplayColumns",
    type: "GET",
    "data": {
        "dataStoreName": "test"
    }
}).done( function( displayColumns ) {
    var requestTable = $( '#adjustmentRequests' ).dataTable( {
        "jQueryUI": true,
        "paging": false,
        "searching": false,
        "info": false,
        "processing": true,
        "ajax": {
            "url": "getData",
            "data": {
                "itemId": "1234"
            }
        },
        "columns": displayColumns,
        "columnDefs": [
            { // Date columns
                "targets": "date",
                "render": function( data, type, row ) {
                    if( data == "1/1/1900" ) {
                        return null;
                    }

                    return data;
                }
            },
            { // Money columns
                "targets": "money",
                "render": function( data, type, row ) {
                    var className = new Number( data ) > 0 ? "positiveAmount" : "negativeAmount";
                    return "<span class='" + className + "'>" + data + "</span>";
                }
            }
        ],
        "language": { "emptyTable": "<span style='font-style:italic'>No adjustments requested.</span>" }
    });
});

Example response from getDisplayColumns:

[
{"name":"Code","orderable":true,"searchable":true,"title":"Code","visible":true},
{"className":"money","name":"Amount","orderable":true,"searchable":true,"title":"Amount","type":"num","visible":true},
{"className":"date","name":"Requested On","orderable":true,"searchable":true,"title":"Requested On","type":"date","visible":true}
]

Example response from getData:

[
[42, 23410000.00, 02/25/2015], 
[A1134, -42.70, 02/24/2015]
]

Why is DataTables unable to perform the format rendering? Does it have to do with the columns coming from AJAX instead of the DOM? Have I missed something else?

Any assistance would be appreciated.

This question has an accepted answers - jump to answer

Answers

  • barenabarena Posts: 3Questions: 1Answers: 0
    edited March 2015

    I've narrowed this down to a more manageable issue that I'm hoping someone can quickly explain. Here is the example.

    As you can see, the columnDefs.targets property is not working. The style is applied to the "Amount" column from the CSS class "money", but the changes specified in columnDefs (disabling sorting on the column) are not applied. If you change the "targets" from "money" to the column index 1 then it works. If you define the <th> in the HTML DOM instead of via javascript then it also works. This appears to be a defect or missing functionality.

    Is this a bug or am I missing something?

  • allanallan Posts: 63,679Questions: 1Answers: 10,498 Site admin
    Answer ✓

    I'm not sure if this is a bug or not, but certainly a gotcha... The targets has to be evaluated before the columns are created (so DataTables know how many columns to create) so the class name hasn't been assigned to the columns, since they don't exist yet. Therefore there isn't a money class column.

    I'm inclined to suggest that it isn't a bug for this reason, however it would be nice if I could handle it more gracefully...! I'm just not sure how at the moment (without adding a fair chunk of code to the core library).

    Allan

  • barenabarena Posts: 3Questions: 1Answers: 0

    Allan, thanks for the response. I can certainly understand your perspective. One of my coworkers helped me come up with a solution, and perhaps it will assist you in adding this functionality in the future. It is detailed below:

    /**
     * Get an array of indexes for columns that have the given class name.
     *
     * @param columns list of DataTables column objects
     * @param className name of the class to look for
     * @returns array of indexes
     */
    function getColumnIndexesWithClass( columns, className ) {
        var indexes = [];
        $.each( columns, function( index, columnInfo ) {
            // note: doesn't attempt to support multiple class names on a column
            if( columnInfo.className == className ) {
                indexes.push( index );
            }
        } );
    
        return indexes;
    }
    
      var table = $('#example').dataTable( {
            "columns": displayColumns,
            "data": dataSet,
            "columnDefs": [
                { // prevent ordering on the Amount column
                  "targets": getColumnIndexesWithClass( displayColumns, "money" ),
                  "orderable": false
                }
            ]
      } );
    

    This solution is pretty easy to implement, and with some enhancement for additional border cases this could possibly be a nice addition to the core library.

  • allanallan Posts: 63,679Questions: 1Answers: 10,498 Site admin

    It should probably be:

    var re = '/\b'+className+'\b/';
    if ( re.match( className ) ) {
      ...
    }
    

    (I haven't tested it, but I think that is correct... :-). That way you can specify more than one class.

    I'll certainly have a look at putting this in the core. Thanks for the feedback!

    Allan

This discussion has been closed.