row toggle plug in

row toggle plug in

datahandlerdatahandler Posts: 26Questions: 2Answers: 1

Hello,

I am completely new to this forum and to developing plug-ins, so please go easy on me.

I have followed the 'Sliding child rows' tutorial here and have used this functionality in my own web pages. But it occurred to me that I could create a plug-in to do some of the work for me.

Below is what I have come up with so far. Before I go any further with it (if indeed I do, depending on feedback), I though I'd open it up to the forum for discussion.

(function($) {
    var ToggleRow = function ( dt ) {
        this.toggle = function( dtRow ) {
            // if row already showing, close it.
            if (dtRow.child.isShown()) {                
                this.closeRow( dtRow );
            }
            else {
                showRowData( dtRow );
            }           
        };
        // code borrowed from the resource at: https://datatables.net/blog/2014-10-02
        this.closeRow = function ( dtRow ) {
            var showingRow = $(dtRow.node());            

            $('div.slider', dtRow.child()).slideUp(function () {
                dtRow.child.remove();
                showingRow.removeClass('shown');
                
                $(dt.table().node()).trigger('rowClosed', [dtRow]);
            });
        };
        var showRow = this.showRow = function ( dtRow, data ) {
            var selectedRow = $(dtRow.node());
            dtRow.child(data).show();                       

            $('div.slider', dtRow.child()).slideDown(function () {
                selectedRow.addClass('shown');
                
                $(dt.table().node()).trigger('rowShown', [dtRow]);
            });
        };
        // relies on data attributes being present for the row being toggled
        var showRowData = function ( dtRow ) {
            var row = $(dtRow.node());
            var requestType = row.data('request-type') || "GET";
            var requestUrl = row.data('request-url');
            var requestData = row.data('request-data') || null;
            var contentType = row.data('content-type') || "application/json; charset=utf-8";
            var dataType = row.data('data-type') || "json";
            var callback = row.data('callback');
            $.ajax({
                type: requestType,
                url: requestUrl,
                data: requestData,
                contentType: contentType,
                dataType: dataType,
                success: function ( response ) {
                    var data = response;
                    if (callback) {
                        var fn = window[callback];
                        if (fn) data = fn(response);
                    }
                    showRow( dtRow, data );
                },
                error: function (response) { showRow( dtRow, response ); }
            });
        };
    };

    $.fn.dataTable.ToggleRow = ToggleRow;
    $.fn.DataTable.ToggleRow = ToggleRow;
}(jQuery));

Thanks in advance to anyone who cares to comment on this endeavour

This question has accepted answers - jump to:

Answers

  • tangerinetangerine Posts: 3,365Questions: 39Answers: 395

    It would be better to provide a link showing this in action.

  • datahandlerdatahandler Posts: 26Questions: 2Answers: 1

    Hi tangerine. Thanks for your response. I'll try to get a link sorted this week and post it here

  • datahandlerdatahandler Posts: 26Questions: 2Answers: 1

    Hi tangerine. As promised, I have made a demo available here:

    http://datahandler.uk/

    Regards

  • tangerinetangerine Posts: 3,365Questions: 39Answers: 395

    @Allan: your comments would be far more useful than mine....

  • allanallan Posts: 63,350Questions: 1Answers: 10,443 Site admin
    Answer ✓

    I think that looks great - thanks for sharing you work with us. I'm sure others will find it useful. The sliding child rows is something that I know is quite popular.

    In terms of suggestions for how to progress this:

    1. Perhaps move the toggling code into the plug-in. Most of my own extensions that use event listeners have a selector type option, which will add the listener automatically for the end user (you'd be surprised how few developers want to add their own listeners!).
    2. Make the Ajax stuff configurable via an options parameter that can be passed in. Using the data-* attributes obviously works well for your project, but I suspect most people will want to set a specific URL and send, e.g., the row id, to get the child information from a common location.

    Nice one :smile:.

    Allan

  • datahandlerdatahandler Posts: 26Questions: 2Answers: 1
    edited January 2017

    Hi Allan,

    Thanks for the positive feedback and thank you for the suggestions.

    I will develop this further and post the results back here.

    Nick

  • allanallan Posts: 63,350Questions: 1Answers: 10,443 Site admin
    Answer ✓

    Hi Nick,

    Would be very happy to include it in the DataTables plug-ins repo if you'd like to send a PR with your code here. A new directory called "slidingChild" or similar (I feel "RowToggle" might be a little too generic, since it could toggle various things and doesn't specifically mention the child row) - but I'll leave it up to you!

    The code in the plug-ins repo is all MIT licensed if you are okay with that.

    Allan

  • datahandlerdatahandler Posts: 26Questions: 2Answers: 1

    Hi Allan,

    that's brilliant. Will do.

    Thank you,
    Nick

  • datahandlerdatahandler Posts: 26Questions: 2Answers: 1

    Hi Allan,

    I've sent a pull request, but having never done one before, I'm note sure if I have done it correctly. In case I haven't, I've included the js and css below.

    Thanks
    Nick

    /**
     * @summary     SlidingChild
     * @description Plug-in to show/hide row child data
     * @version     1.0.0
     * @file        slidingchild.js
     * @author      datahandler (www.datahandler.uk)
     * @copyright   Copyright 2014 SpryMedia Ltd.
     * 
     * License      MIT - http://datatables.net/license/mit
     */
    
    /**
     * Example usage
     * @example
     * var table = $('#table_id').DataTable();
     * slidingChild =
     *     new $.fn.dataTable.SlidingChild(table, {
     *         ajax: {
     *             requestType: 'POST',
     *             requestUrl: '/Home/GetChildData',
     *             dataType: 'HTML',
     *             requestDataCallback: myRequestDataCallback
     *         }
     *     });
     */
    (function ($) {
        var SlidingChild = function (dt, options) {
            var opts = $.extend({}, SlidingChild.defaults, options);
    
            // bind to selector click
            $(opts.selector).on('click', function () {
                var $this = $(this);
                var dtRow = $this.is('tr') ? $this : $this.closest('tr');
    
                if (!dtRow.is('tr')) { return; } // throw error?
                // check row belongs to this table?
    
                dtRow = dt.row(dtRow);
                toggleChild(dtRow);
            });
    
            var toggleChild = function (dtRow) {
                // if child already showing, close it.
                if (dtRow.child.isShown()) {
                    closeChild(dtRow);
                }
                else {
                    // closes existing showing child, if any
                    if (opts.toggleChild) closeChild(dt.row('.shown'));
    
                    showChildData(dtRow);
                }
            };
            // code borrowed from the resource at: https://datatables.net/blog/2014-10-02
            var closeChild = function (dtRow) {
                if (dtRow) {
                    var showingRow = $(dtRow.node());
                    $(opts.sliderSelector, dtRow.child()).slideUp(function () {
                        dtRow.child.remove();
                        showingRow.removeClass('shown');
                        $(dt.table().node()).trigger('childClosed', [dtRow]);
                    });
                }
            };
    
            var showChildData = function (dtRow) {
                if (opts.useRowData) {
                    showChildDataFromRow(dtRow);
                }
                else {
                    $.ajax({
                        type: opts.ajax.requestType,
                        url: opts.ajax.requestUrl,
                        beforeSend: function(xhr, settings) {
                            if (opts.ajax.requestDataCallback) {
                                this.data = opts.ajax.requestDataCallback(dtRow);
                            }
                        },
                        contentType: opts.ajax.contentType,
                        dataType: opts.ajax.dataType,
                        success: function (response) {
                            var data = response;
                            if (opts.dataFormatCallback) {
                                data = opts.dataFormatCallback(response);
                            }
                            showChild(dtRow, data);
                        },
                        error: function (response) { showChild(dtRow, response); }
                    });
                }
            };
    
            var showChildDataFromRow = function(dtRow) {
                if (!opts.dataFormatCallback) { return; } // throw error?
                var data = opts.dataFormatCallback(dtRow.data());
                showChild(dtRow, data);
            }
    
            var showChild = function(dtRow, data) {
                var selectedRow = $(dtRow.node());
                dtRow.child(data).show();
    
                $(opts.sliderSelector, dtRow.child()).slideDown(function () {
                    selectedRow.addClass('shown');
    
                    $(dt.table().node()).trigger('childShown', [dtRow]);
                });
            };
        };
    
        SlidingChild.defaults = {
            selector: "tr",
            toggleChild: false,
            useRowData: false,
            ajax: {
                requestType: "GET",
                requestDataCallback: null,
                requestUrl: null,
                contentType: "application/json; charset=utf-8",
                dataType: "json"
            },
            dataFormatCallback: null,
            sliderSelector: 'div.slider'
        };
    
        $.fn.dataTable.SlidingChild = SlidingChild;
        $.fn.DataTable.SlidingChild = SlidingChild;    
    }(jQuery));
    
    div.slider {
        padding-top:2px;
        display: none;
    }
    
This discussion has been closed.