JSFiddle - React, Tailwind, and code Playground

getSortable

by Jennifer Perrin

HTML

<table>
    <tr>
        <th id="facility_header">Facility name</th>
        <th>Phone #</th>
        <th id="city_header">City</th>
        <th>Speciality</th>
    </tr>
    <tr>
        <td>CCC</td>
        <td>00001111</td>
        <td>Amsterdam</td>
        <td>GGG</td>
    </tr>
    <tr>
        <td>JJJ</td>
        <td>55544444</td>
        <td>London</td>
        <td>MMM</td>
    </tr>
    <tr>
        <td>AAA</td>
        <td>33332222</td>
        <td>Paris</td>
        <td>RRR</td>
    </tr>
</table>

CSS

td, th {
    border: 1px solid #111;
    padding: 6px;
}
th {
    font-weight: 700;
}

JavaScript

jQuery.fn.sortElements = (function () {

    var sort = [].sort;

    return function (comparator, getSortable) {

        getSortable = getSortable || function () {
            return this;
        };

        var placements = this.map(function () {

            var sortElement = getSortable.call(this),
                parentNode = sortElement.parentNode,

                // Since the element itself will change position, we have
                // to have some way of storing it's original position in
                // the DOM. The easiest way is to have a 'flag' node:
                nextSibling = parentNode.insertBefore(
                document.createTextNode(''),
                sortElement.nextSibling);

            return function () {

                if (parentNode === this) {
                    throw new Error(
                        "You can't sort elements if any one is a descendant of another.");
                }

                // Insert before flag:
                parentNode.insertBefore(this, nextSibling);
                // Remove flag:
                parentNode.removeChild(nextSibling);

            };

        });

        return sort.call(this, comparator).each(function (i) {
            placements[i].call(getSortable.call(this));
        });

    };

})();

var table = $('table');

$('#facility_header, #city_header')
    .wrapInner('<span title="sort this column"/>')
    .each(function () {

    var th = $(this),
        thIndex = th.index(),
        inverse = false;

    th.click(function () {

        table.find('td').filter(function () {

            return $(this).index() === thIndex;

        }).sortElements(function (a, b) {

            return $.text([a]) > $.text([b]) ? inverse ? -1 : 1 : inverse ? 1 : -1;

        }, function () {

            // parentNode is the element we want to move
            return this.parentNode;

        });

        inverse = !inverse;

    });

});