Datatable and data-attribute HTML5 instead of JS init way

Datatable and data-attribute HTML5 instead of JS init way

VadorequestVadorequest Posts: 16Questions: 6Answers: 0
edited May 2014 in Feature requests

I read a lot the documentation today and I have the feeling that something is missing.
We can initialize the datatable using javascript, but there is no way to help us to initialize using HTML5 data-attribute.

Don't you think that allow to use things like <tr data-datatable-type="date-euro">€</tr> would improve a lot the use of datatable?

I mean, the javascript way is the most important, of course, but sometimes it's just much faster to configure the table using html5 than JS. The JS should be able to override the html5 attribute if provided.

In this specific example, it would also avoid to stronly link the column number with the javascript, not like here:

"columnDefs": [
    { "type": "numeric-comma", targets: 3 }
]

I really think that provide such configuration way would improve a lot the use of the datatable and void to use JS when we could do it with HTML5.

What do you think about that? Many API use this system nowoday, that will become a standard way to configure plugins like jQuery.datatable.

Answers

  • allanallan Posts: 63,489Questions: 1Answers: 10,470 Site admin

    I've been planning on writing a plug-in for DataTables that would provide this functionality for a long time, and just never had the change to do it. This question do come up a few times a year and it is something I very much want to do - its just a question of getting the time to do it as there are so many other things that are currently taking priority!

    Regards,
    Allan

  • VadorequestVadorequest Posts: 16Questions: 6Answers: 0

    Okay, do you have any headline/doc about how you thought you would have implemented that? Any idea how much time is required? I'm wondering about doing it myself. (PR)

  • allanallan Posts: 63,489Questions: 1Answers: 10,470 Site admin

    The approach I'd take myself is simply to have a mapping object of data attributes to DataTables properties and then loop over the object, searching the DOM for the required parameters and building an initialisation object. There are all sorts of things you could do such as being clever with columns (this is the default sort column), etc, so it could be the work of a few hours, or it could be days of work :-)

    Allan

  • VadorequestVadorequest Posts: 16Questions: 6Answers: 0

    I just discovered that it already "exists", not to type column but some implementation is already done.

    https://datatables.net/manual/orthogonal-data
    https://datatables.net/examples/advanced_init/html5-data-attributes.html

  • allanallan Posts: 63,489Questions: 1Answers: 10,470 Site admin

    That's for orthogonal data and not initialisation parameters.

    Allan

  • gatesw81gatesw81 Posts: 2Questions: 1Answers: 0

    I wrote this plugin do to it -

    http://jsfiddle.net/x6ddqqe7/1/

    Supports setup on document ready or when table element has .initiaTable() called on it.

    (function (jQuery) {
        var initiaTable = {};
    
        /*Because HTML 5 attributes do not allow casing we need to map.*/
        var dtPropMap = {
            /*DataTables Base*/
            autowidth: "autoWidth",
            deferrender: "deferRender",
            info: "info",
            jqueryui: "jQueryUI",
            lengthchange: "lengthChange",
            ordering: "ordering",
            paging: "paging",
            processing: "processing",
            scrollx: "scrollX",
            scrolly: "scrollY",
            searching: "searching",
            serverSide: "serverSide",
            statesave: "stateSave",
            data: "data",
            ajax: "ajax",
            createdrow: "createdRow",
            drawcallback: "drawCallback",
            footercallback: "footerCallback",
            formatnumber: "formatNumber",
            headercallback: "headerCallback",
            infocallback: "infoCallback",
            initcomplete: "initComplete",
            predrawcallback: "preDrawCallback",
            rowcallback: "rowCallback",
            stateloadcallback: "stateLoadCallback",
            stateloaded: "stateLoaded",
            stateloadparams: "stateLoadParams",
            statesavecallback: "stateSaveCallback",
            statesaveparams: "stateSaveParams",
            deferloading: "deferLoading",
            destroy: "destroy",
            displaystart: "displayStart",
            dom: "dom",
            lengthmenu: "lengthMenu",
            ordercellstop: "orderCellsTop",
            orderclasses: "orderClasses",
            order: "order",
            orderfixed: "orderFixed",
            ordermulti: "orderMulti",
            pagelength: "pageLength",
            pagingtype: "pagingType",
            renderer: "renderer",
            retrieve: "retrieve",
            scrollcollapse: "scrollCollapse",
            search: "search",
            stateduration: "stateDuration",
            stripeclasses: "stripeClasses",
            tabindex: "tabIndex",
            columndefs: "columnDefs",
            columns: "columns",
            language: "language",
    
            /*TableTools*/
            tabletools: "tableTools",
    
            /*Scroller*/
            scroller: "scroller",
    
            /*Responsive*/
            responsive: "responsive"
        };
    
        if (typeof String.prototype.startsWith != 'function') {
            String.prototype.startsWith = function (str) {
                return this.slice(0, str.length) == str;
            };
        }
    
        initiaTable.getValueFromString = function (funcName, onObject) {
            if (typeof funcName != "string") {
                return funcName;
            }
    
            /*If onObject is null it means we are on the first pass and should check a couple of special cases*/
            if (!onObject) {
                onObject = window;
    
                /*See if we are dealing with a boolean*/
                switch (funcName.toUpperCase()) {
                    case 'TRUE':
                        return true;
                    case 'FALSE':
                        return false;
                }
    
                /*See if we are dealing with a number*/
                try {
                    var num = parseInt.parse(funcName);
                    return num;
                } catch (e) { }
    
                /*See if we are dealing with a dynamic object*/
                try {
                    var fixedResponse = funcName.replace(/\'/g, "\"");
                    var parsedObj = JSON.parse(fixedResponse);
                    return initiaTable.getValueFromString(parsedObj);
                } catch (e) { }
    
                /*See if we are dealing with a dynamic function*/
                try {
                    var dynamicFunctString = '(' + funcName + ')';
                    var dynamicFunct = eval(dynamicFunctString);
                    if (typeof dynamicFunct === 'function') {
                        return dynamicFunct;
                    }
                } catch (e) { }
            }
    
            /*We are likely dealing with a pointer or a raw string. Determine if its a valid pointer for an object or function*/
            var dotIndex = funcName.indexOf('.');
            if (dotIndex > 0) {
                var str = funcName.substr(0, dotIndex);
                var fn = onObject[str];
                if (typeof fn === 'object' || typeof fn === 'function') {
                    var next = funcName.slice(dotIndex + 1);
                    return initiaTable.getValueFromString(next, fn);
                }
            } else {
                var parenIndex = funcName.indexOf('(');
                if (parenIndex > 0) {
                    var endParen = funcName.indexOf(')');
                    var func = funcName.slice(0, parenIndex);
                    var params = JSON.parse("[" + funcName.slice(parenIndex + 1, endParen) + "]");
                    if ($.isFunction(onObject[func])) {
                        return onObject[func].apply(onObject, params);
                    }
                } else {
                    var fn = onObject[funcName];
                    return fn;
                }
            }
        };
    
        initiaTable.getConfigValue = function (value) {
            var dtConfigValue = initiaTable.getValueFromString(value);
            return typeof dtConfigValue !== 'undefined' ? dtConfigValue : value;
        };
    
        initiaTable.getDataTableConfig = function (table) {
            var $table = $(table);
            /*We want to destroy the table so we don't accidentally try to initialize it twice*/
            var tableConfig = { destroy: true }
            var columns = [];
    
            /*Table Configs*/
            $.each($table.data(), function (key, value) {
                if (key.startsWith('dt_')) {
                    var dtTblProp = dtPropMap[key.substring(3, key.length)];
                    tableConfig[dtTblProp] = initiaTable.getConfigValue(value);
                }
            });
    
            /*Column Configs*/
            $("thead th", table).each(function () {
                var columnConfig = {};
                $.each($(this).data(), function (key, value) {
                    if (key.startsWith('dt_')) {
                        var dtColProp = dtPropMap[key.substring(3, key.length)];
                        columnConfig[dtColProp] = initiaTable.getConfigValue(value);
                    }
                });
                columns.push(columnConfig);
            });
    
            if (columns.length > 0) {
                tableConfig.columns = columns;
            }
    
            return tableConfig;
        };
    
        initiaTable.initializeDataTable = function (params) {
            var config = initiaTable.getDataTableConfig(this);
            var datatable = $(this).dataTable(config);
            $(this).removeAttr('data-role');
    
            return datatable;
        };
    
        $.fn.initializeDataTables = function () {
            $(this).each(function () {
                $(this).initiaTable();
            });
            return this;
        };
    
        /*Expose internal methods for callers - Useful if caller wants to grab the config json without actually initializing a table.*/
        $.fn.initiaTable = function (method) {
            if (initiaTable[method]) {
                return initiaTable[method].apply(this, Array.prototype.slice.call(arguments, 1));
            }
            else if (typeof method === 'object' || !method) {
                return initiaTable.initializeDataTable.apply(this, arguments);
            }
    
            $.error('Method ' + method + ' does not exist on jQuery.initiaTable');
        };
    
        /* Verify that DataTables is loaded and the version is supported */
        if (!(typeof $.fn.dataTable == "function" &&
              typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
              $.fn.dataTableExt.fnVersionCheck('1.10.0'))) {
            alert("Warning: initiaTable 2 requires DataTables 1.10.0 or newer - www.datatables.net/download");
        }
    })(jQuery);
    
    $(document).ready(function () {
        $('table[data-role="datatable"]').initializeDataTables();
    
        $('body').bind('initialize', function (event) { $(event.target).initializeDataTables(); });
    });
    
  • allanallan Posts: 63,489Questions: 1Answers: 10,470 Site admin

    Thanks for sharing your solution with us!

    You might also be interested in checking out this Github thread which discusses something similar. I'm still considering this for DataTables core (haven't had time to properly look into it yet!).

    Allan

This discussion has been closed.