Git Product home page Git Product logo

sortable's Introduction

sortable

- a tiny, vanilla/plain JavaScript table sorter

GitHub Issues or Pull Requests NPM Version NPM Downloads GitHub Repo stars jsdelivr

Makes any table with class="sortable", er, sortable. The user can click on a table header and change the sorting of the table rows.

Just include the JavaScript and it will work. No function calls are needed, everything is handled by an eventListener.

Demo

You can find a simple demo on https://tofsjonas.github.io/sortable/

Table of Contents

Factoids

  • 1148 bytes minified. (619 bytes gzipped)

  • Works with JavaScript generated tables. (since we are using an eventListener)

  • Lightning fast. Huge tables will make it slow and may freeze the browser, especially for mobiles, so you know...

  • Requires thead and tbody.

  • rowspan is not supported 😢

  • cross browser, ie9+ No longer ie9 compatible. Then again, maybe it already wasn't 🤷

  • NOT tested with React, Angular, Vue, etc.

  • Works with Svelte!

"Installation"

There are three ways to use sortable, all of which have their pros and cons. S Anand and dkhgh had some interesting thoughts about it.

  1. Include a link to jsDelivr. (easiest)

  2. Copy the file from jsDelivr or Github and put it in your assets folder. (in between)

  3. Install the npm package. (most reliable)

1. link to jsDelivr

<table class="sortable">
  <thead>
    <tr>
      <th><span>Role</span></th>
      <th>Name</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Genius</td>
      <td>Rick</td>
    </tr>
    <tr>
      <td><a href="javascript:alert('Inline javascript works!');">Sidekick</a></td>
      <td>Morty</td>
    </tr>
  </tbody>
</table>
<link href="https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/sortable.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/sortable.min.js"></script>

The span on line four is just there to prove that you can have elements inside th!

⚠️ If you are concerned about bugs, I recommend using version numbers instead of "latest".

2. copy file to assets folder

Same as above, but link to your own files

...
<link href="/assets/sortable.min.css" rel="stylesheet" />
<script src="/assets/sortable.min.js"></script>
...

3. npm package

First,

npm install sortable-tablesort
# yarn add sortable-tablesort
# pnpm install sortable-tablesort

Now you can

a) use links in the html

Same as above, with links to files

...
<link href="./node_modules/sortable-tablesort/sortable.min.css" rel="stylesheet" />
<script src="./node_modules/sortable-tablesort/sortable.min.js"></script>
...

or

b) import files in javascript

// main.js
import 'sortable-tablesort/sortable.min.css'
import 'sortable-tablesort/sortable.min.js'

Non-sortable field

...using class="no-sort"

If you wish to disable sorting for a specific field, the easiest (and best) way is to add class="no-sort" to it, like so:

<thead>
  <tr>
    <th class="no-sort">Role</th>
    <th>Name</th>
  </tr>
</thead>

Sorting will not be triggered if you click on "Role".

...using CSS

This is a bit trickier, but it doesn't require any changes to the html, so I guess it could be worth it in some cases.

/* the first column in every sortable table should not be sortable*/
.sortable th:nth-child(1) {
  pointer-events: none;
}

/* the seventh column in the second .sortable table should not be sortable*/
.sortable:nth-of-type(2) th:nth-child(7) {
  pointer-events: none;
}

...using td instead of th

The eventListener only triggers on th, not td, so this would disable sorting for "Role":

<thead>
  <tr>
    <td>Role</td>
    <th>Name</th>
  </tr>
</thead>

⚠️ Since th and td are not the same thing, you would most likely still have to use CSS to make them look the way you want. (It might also mess with accessibility.) In some cases it could be worth it, but I recommend the .no-sort alternative.

Indicators/arrows on the left side

If you have text that is aligned on the right side, you may want to have the arrows on the left side.

This is solved by adding a class to the css and using ::before instead of ::after.

(You can of course use a pure css solution, without class names - just like with the non-sortable field - but that I will leave for you to figure out.)

.sortable th.indicator-left::after {
  content: '';
}
.sortable th.indicator-left::before {
  margin-right: 3px;
  content: '▸';
}
/* etc. */

Full example: CSS, SCSS

NOTE ABOUT CSS/SCSS

The css/scss in this repo was only ever meant as an example. It was never intended to be actually used.

That said, if you're feeling lazy, here are two stylesheets you can use:

<!-- This will add arrows, as well as support for .no-sort and .indicator-left -->
<link href="https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/sortable-base.min.css" rel="stylesheet" />

<!-- This will make it look like the tables in the example, with arrows, striped rows etc. -->
<link href="https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/sortable.min.css" rel="stylesheet" />

Sorting sizes, dates and such

Using the data-sort attribute in tbody > td you can have one visible value and one sortable value. This is useful in case you have for instance sizes like kb, Mb, GB, or really weird date formats. 😉

<table class="sortable">
  <thead>
    <tr>
      <th>Movie Name</th>
      <th>Size</th>
      <th>Release date</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Zack Snyder's Justice League</td>
      <td data-sort="943718400">900MB</td>
      <td data-sort="20210318">03/18/2021</td>
    </tr>
    <tr>
      <td>The Sound of Music</td>
      <td data-sort="1610612736">1.5GB</td>
      <td data-sort="19651209">12/09/1965</td>
    </tr>
  </tbody>
</table>

Alternative sorting

If you click on a table header while holding shift or alt an alternative data-sort-alt attribute will override data-sort.

<table class="sortable">
  <thead>
    <tr>
      <th>Movie Name</th>
      <th>Size</th>
      <th>Release date</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Something</td>
      <td data-sort-alt="c" data-sort="a">A</td>
      <td data-sort-alt="b" data-sort="c">B</td>
      <td data-sort-alt="a" data-sort="b">C</td>
    </tr>
    <tr>
      <td>Something else</td>
      <td data-sort-alt="e" data-sort="f">D</td>
      <td data-sort-alt="f" data-sort="e">E</td>
      <td data-sort-alt="d" data-sort="d">F</td>
    </tr>
  </tbody>
</table>

Colspans/Sort on specific column

Using the data-sort-col attribute in thead > th, you can sort on a different column than the one that was clicked. For instance if you want to have colspans. Like so:

<thead>
  <tr>
    <th></th>
    <th>Category</th>
    <th class="show_name">Show</th>
    <th colspan="2">Overall</th>
    <th colspan="2" data-sort-col="5">On Our Dates</th>
    <th data-sort-col="7">First Sold Out</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td class="tags">&nbsp;</td>
    <td class="category">Comedy</td>
    <td class="show_name">Show 1</td>
    <td class="ratio all" data-sort="72">18/25</td>
    <td class="pct all">72%</td>
    <td class="ratio ours" data-sort="75">3/4</td>
    <td class="pct ours">75%</td>
    <td>2022-07-30</td>
  </tr>
  ...
</tbody>

Concerning rowspan

Rowspans are not supported. Maybe I could do a half-assed implementation, but I don't think it would be worth it. You can read my justification in Issue 71

If you have a good idea, please let me know!

Ascending sort

By adding asc to table, the default sorting direction will be ascending instead of descending

<table class="sortable asc">
  <thead>
    ...
  </thead>
  <tbody>
    ...
  </tbody>
</table>

Tiebreaker / secondary sort

If you wish to sort by a different column when two values are equal, you can use the data-sort-tbr attribute, like so:

<table class="sortable asc">
  <thead>
    <tr>
      <th data-sort-tbr="1">Year</th>
      <th>Month</th>
      <th>Day</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>2010</td>
      <td>07</td>
      <td>25</td>
    </tr>
    <tr>
      <td>2010</td>
      <td>11</td>
      <td>12</td>
    </tr>
    <tr>
      <td>2010</td>
      <td>04</td>
      <td>25</td>
    </tr>
  </tbody>
</table>

When clicking Year, if they are the same, we will sort on Month.

Empty/null rows always last

Adding class="n-last" to <table class="sortable"> will make empty/null values always be sorted last, similar to what SQL does with ORDER BY foo NULLS LAST.

<table class="sortable n-last">
  <thead>
    <tr>
      <th>Text</th>
      <th class="indicator-left">Number</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>jkl</td>
      <td>0.4</td>
    </tr>
    <tr>
      <td>This will always be sorted after the others</td>
      <td></td>
    </tr>
    <tr>
      <td>abc</td>
      <td>0</td>
    </tr>
    <tr>
      <td>def</td>
      <td>0.2</td>
    </tr>
  </tbody>
</table>

⚠️ Note that a string of blank spaces is not considered null/empty. <td data-sort=" "></td> will be sorted normally.

Accessibility

Sortable is not very accessible in its raw form. It does not support screen readers, and it does not have any keyboard support. Including sortable.a11y.min.js in your project will add some basic accessibility features.

<table class="sortable">
  ...
</table>
<link href="sortable.min.css" rel="stylesheet" />
<script src="sortable.min.js"></script>
<script src="sortable.a11y.min.js"></script>

By including the file the global function enhanceSortableAccessibility will automatically run through all existing .sortable tables, but you can also run it manually, like so:

enhanceSortableAccessibility([table1, table2,...etc.])

The function adds an aria-label to each th, as well as tabindex="0" to each th in the thead of each table, making it possible to tab through the headers. It updates the aria-label depending on the direction.

if you want to import it instead this should work: (I haven't tested it)

import { enhanceSortableAccessibility } from 'sortable-tablesort/enhanceSortableAccessibility'
enhanceSortableAccessibility([table1, table2,...etc.])

Sort on load

If you wish to sort a table on load, I would recommend doing something like this:

<table class="sortable">
  <thead>
    <tr>
      <th>Movie Name</th>
      <th id="movie-size">Size</th>
      <th>Release date</th>
    </tr>
  </thead>
  <tbody>
    ...
  </tbody>
</table>

<script>
  window.addEventListener('load', function () {
    const el = document.getElementById('movie-size')
    // without id:
    // const el = document.querySelector('.sortable th:first-child')
    // const el = document.querySelector('.sortable th:nth-child(2)')
    // const el = document.querySelectorAll('.sortable')[3].querySelector('th:nth-child(7)')
    // etc.
    if (el) {
      el.click()
    }
  })
</script>

Combine this with <table class="sortable asc"> to reverse the sort order. Or do el.click() twice!

Thank you...

sortable's People

Contributors

elmartinezc avatar mmitch avatar quelbs avatar tofsjonas avatar tofsmachine avatar wodny avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sortable's Issues

Sort by anything other then string

Nice simple sort tool. But it can't handle anything special it seems. Can't sort by date or memory size or version number.....

So would be nice to add some of these as an option.

Secondary sort

To illustrate a practical example:

I have a table with many rows, each row has a year property.
If I sort by year all entries with the same year are grouped, but within that group, their order is random.

Is there a way to sort by a certain column/property, but also specify a secondary sort (applied when the primary sort values are the same)?

Right off the bat, I imagine I could do something like data-sort="2022-projectname" where I concatenate the year and desired property, but I was wondering if there's perhaps a different way...

Thanks for the help, love the library!

data with title not sorted correctly

I have a column with names in - some have titles, some do not. Names with titles do not appear to be sorted correctly.

Example 'Mrs. N' shows before names starting with 'A' when sorting ascending.

Not sure if the period is causing an issue?

Empty rows always last possible?

Is it possible to make empty rows always last after sorting? Similar to what SQL does with ORDER BY foo NULLS LAST.

So that no matter ascending or descending sort is applied on a column, empty values will always be at the bottom.

No Licence set

I'd like to use this library in my project, but it doesn't have a Licence set. Could you add one please?

Time values are not sorted

Time values like "12:15:10", "12:15:00", "12:15:05" are not sorted, probably because parseFloat returns "12" in all cases.

no-sort too strict?

I tried to add filter inputs to the header to hide or show rows onKeyDown but the no-sort class won't let me click on the inputs to search.

What would be better, ignore the click if TH has the class in javascript or moving the filter inputs outside the table?

chrome_SvkSXeRaQV

Tables with rowspans not sortable

For a table with rowspan="n", the sorting leads to a broken table display. Here's an example:

<html><body>
<table class="sortable">
  <thead>
    <tr>
        <th>Class</th>
      <th><span>Role</span></th>
      <th>Name</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td rowspan="2">Main Character</td>
      <td>Aenius</td>
      <td>Bird Person</td>
    </tr>
    <tr>
      <td>Genius</td>
      <td>Rick</td>
    </tr>
    <tr>
        <td>Comic Relief</td>
      <td><a href="javascript:alert('Inline javascript works!');">Sidekick</a></td>
      <td>Morty</td>
    </tr>
  </tbody>
</table>
<link href="/assets/sortable.min.css" rel="stylesheet" />
<script src="/assets/sortable.min.js"></script>
    </body></html>

Expected result: It treats a rowspan as a single row for sorting purposes.
Actual result: The table is scrambled, sometimes columns are added.

before
after1

(Suggestion) Put the arrows inside the padding

If you text-align to the right you have something like this.

image

In the header there's a space for the arrows.

If we do this:

th {
  position: relative;
}
th::after {
  position: absolute;
}

we can put the arrows inside the padding and the text always aligns in th and td (assuming same text-align)

Error raised in getValue function if click occurs while a table is changing

I have a table that can be many thousands of rows long, so I load 100 in the initial page load and then use fetch to append more rows 1000 at a time.

I'm running into a situation where if a column is clicked while data is still loading getValue throws an error and the table doesn't sort.

TypeError: Cannot read properties of undefined (reading 'dataset')
    at getValue (sortable-27aa9e4755817a61c6c3ea3b85a095c3066bd56a8b951be2714ae9532957a6f8.js:61:80)
    at compare_1 (sortable-27aa9e4755817a61c6c3ea3b85a095c3066bd56a8b951be2714ae9532957a6f8.js:93:25)
    at sortable-27aa9e4755817a61c6c3ea3b85a095c3066bd56a8b951be2714ae9532957a6f8.js:106:32
    at Array.sort (<anonymous>)
    at HTMLDocument.<anonymous> (sortable-27aa9e4755817a61c6c3ea3b85a095c3066bd56a8b951be2714ae9532957a6f8.js:105:22)

As a mitigation I wrapped the code in a try/catch: and just return an empty string.

function getValue(element) {
    try {
        return (alt_sort_1 && element.dataset.sortAlt) || element.dataset.sort || element.textContent;
    }
    catch (error) {
        return '';
    }
}

In a perfect world once a column is sorted I'd love to be able to detect changes to the table and resort it so the appended data isn't just slapped at the bottom of the table. Maybe something like the click() click() from #32 ?

I suppose a partially loaded table not sorting isn't a terrible behavior, but the CSS classes do change as that happens first so it definitely feels broken.

Size sort

Thanks for this sort library @tofsjonas

I tried sortable.mega-advanced but it seems to fail at size sort for some formats such as 100.55 KiB. Is it possible to make sorting work for these kind of values as well?

question: handling 10000 lines & lazy loading

Hi there! Nice project, love your approach from vanilla js.
Does it work well with 10000 lines? I was wondering to use with my small app, that handles time series, which sometimes is quite bulky.

Have you had an experience with a lazy loading (js populates the table when a user scrolls) and sorting and the same time?

Thanks

Problem with element.offsetParent

I had to replace table = element.offsetParent with table = element.parentNode.parentNode.parentNode; because table was changing scope and preventing me from changing sort direction on any column by clicking the column header a second time.

Sort on load

Hi,
Is it possible to get this sorting by a default column and on load instead of click?

A11y: no focus indicators

The progress made recently in A11y is great. Thank you.
In using both
https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/sortable.min.js
https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/sortable.a11y.min.js

There is an issue with not being able to detect visually which heading has focus.
It seems to need something like this in the CSS to make it detectable visually and match the style used for hover. Border size and color is just random suggestion. It needs something visual.

.sortable thead th:not(.no-sort):hover,
.sortable thead th:not(.no-sort):focus {
  outline: 2px solid blue;
}

.sortable thead th:not(.no-sort):focus::after,
.sortable thead th:not(.no-sort):hover::after {
  color: inherit;
}


.sortable thead th:not(.no-sort).indicator-left:focus::before,
.sortable thead th:not(.no-sort).indicator-left:hover::before {
  color: inherit;
}

Accessibility concerns

The headers become clickable but are not actual <a> tags so they can not be accessed with keyboard actions. They are only available to mouse clicks.

Suggested behavior

  • Headers are accessible through tabbing and clicking the enter key to sort.
  • Each header announces to assistive technology what selecting the header will do. (example: Sort <header content> ascending)

Sort table with collapsible rows

Hi, thanks a lot for the code.

I have a table with collapsible / expandable rows that I would like to omit from the sorting. They should remain in the same position relative to their 'parent' row.

I've looked into a few solutions but so far they don't work very well with your code, at least not in an elegant way.
Would you have any proposals?

Demo

Could You please deploy a demo?

Numeric Sort Option

Hey there. Me, again. Have you considered adding a numeric sort option? I know we can currently implement a custom value using the data-sort attribute, however, a native option to sort a column numerically would be awesome.

Current use case, a client has weights entered into a comparison table and they want to sort those values numerically. Currently, without any customization, there is no differentiation between alphanumeric and numeric sorting in the script (that I am aware of, anyway).

I was going to see about adding a numeric sort option using a classname, similar to "no-sort", and wanted to check with you to see if that is already a thing or if it's something you're considering for a future release.

How to sort with colspan?

This works very well for simple sorting, thank you! I've run into two problems, though, and thought I'd ask about them.

  1. How do I set the sort value for a set of columns which are grouped under a single <th> using colspan?
  2. Why aren't ISO dates ("2022-08-08") being sorted correctly?

You can see these issues in the following code:

image

<!DOCTYPE html>
<html>
<body>
    <table class="available sortable">
        <thead>
            <tr>
                <th class=""></th>
                <th class="">Category</th>
                <th class="show_name">Show</th>
                <th colspan="2" class="">Overall</th>
                <th colspan="2" class="">On Our Dates</th>
                <th class=" dir-d ">First Sold Out</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td class="tags">
                    
                        &nbsp;
                    
                </td>
                <td class="category">Comedy</td>
                <td class="show_name">Show 1</td>
                <td class="ratio all" data-sort="72">18/25</td>
                <td class="pct all">72%</td>
                <td class="ratio ours" data-sort="75">3/4</td>
                <td class="pct ours">75%</td>
                <td>2022-07-30</td>
            </tr><tr>
                <td class="tags">
                    
                        &nbsp;
                    
                </td>
                <td class="category">Music</td>
                <td class="show_name">Show 2</td>
                <td class="ratio all" data-sort="60">6/10</td>
                <td class="pct all">60%</td>
                <td class="ratio ours" data-sort="75">3/4</td>
                <td class="pct ours">75%</td>
                <td>2022-08-04</td>
            </tr><tr>
                <td class="tags">
                    
                        &nbsp;
                    
                </td>
                <td class="category">Theatre</td>
                <td class="show_name">Show 3</td>
                <td class="ratio all" data-sort="47">7/15</td>
                <td class="pct all">47%</td>
                <td class="ratio ours" data-sort="75">3/4</td>
                <td class="pct ours">75%</td>
                <td>2022-07-19</td>
            </tr><tr>
                <td class="tags">
                    
                        &nbsp;
                    
                </td>
                <td class="category">Comedy</td>
                <td class="show_name">Show 4</td>
                <td class="ratio all" data-sort="67">10/15</td>
                <td class="pct all">67%</td>
                <td class="ratio ours" data-sort="67">2/3</td>
                <td class="pct ours">67%</td>
                <td>2022-07-19</td>
            </tr><tr>
                <td class="tags">
                    
                        &nbsp;
                    
                </td>
                <td class="category">Comedy</td>
                <td class="show_name">Show 5</td>
                <td class="ratio all" data-sort="75">9/12</td>
                <td class="pct all">75%</td>
                <td class="ratio ours" data-sort="50">1/2</td>
                <td class="pct ours">50%</td>
                <td>2022-07-29</td>
            </tr><tr>
                <td class="tags">
                    
                        &nbsp;
                    
                </td>
                <td class="category">Comedy</td>
                <td class="show_name">Show 6</td>
                <td class="ratio all" data-sort="67">16/24</td>
                <td class="pct all">67%</td>
                <td class="ratio ours" data-sort="50">2/4</td>
                <td class="pct ours">50%</td>
                <td>2022-07-26</td>
            </tr><tr>
                <td class="tags">
                    
                        &nbsp;
                    
                </td>
                <td class="category">Comedy</td>
                <td class="show_name">Show 7</td>
                <td class="ratio all" data-sort="62">16/26</td>
                <td class="pct all">62%</td>
                <td class="ratio ours" data-sort="50">2/4</td>
                <td class="pct ours">50%</td>
                <td>2022-07-31</td>
            </tr>
        </tbody>
    </table>
    <link href="https://tofsjonas.github.io/sortable/sortable.css" rel="stylesheet" />
    <script src="https://tofsjonas.github.io/sortable/sortable.js"></script>
</body>
</html>

Performance improvement suggestions

Huge thanks for great library. So much packed in so few lines of code! :)

Some suggestions:

Final append is done not so efficiently:

        while (rows.length) {
          clone_tbody.appendChild(rows.splice(0, 1)[0])
        }

=>

        clone_tbody.append(...rows)

or

        let l = rows.length;
        for (let j = 0; j < l; j++) {
          clone_tbody.appendChild(rows[j])
        }

Sorting also could be optimized, especially when more than one tbody is present, or no tie breaker specified, by doing specialization before the tBodies loop:

      const tiebreaker = parseInt(element.dataset.sortTbr)

...
    for (let i = 0; i < table.tBodies.length; i++) {
...

        rows.sort(function (a: HTMLTableRowElement, b: HTMLTableRowElement) {
          const bool = compare(a, b, column_index)
          return bool === 0 && !isNaN(tiebreaker) ? compare(a, b, tiebreaker) : bool
        })
...
    }

=>

      const tiebreaker = parseInt(element.dataset.sortTbr)

      let comparator = compare;
      if (!isNaN(tiebreaker)) {
        comparator = function (a: HTMLTableRowElement, b: HTMLTableRowElement) {
          const bool = compare(a, b, column_index)
          return bool === 0  ? compare(a, b, tiebreaker) : bool
        }
      }

    for (let i = 0; i < table.tBodies.length; i++) {

...
        rows.sort(comparator)
...
    }

Same technique can be used for reversing:

      const compare = (a: HTMLTableRowElement, b: HTMLTableRowElement, index: number) => {
        const x = getValue((reverse ? a : b).cells[index])
        const y = getValue((reverse ? b : a).cells[index])
        const temp = parseFloat(x) - parseFloat(y)
        const bool = isNaN(temp) ? x.localeCompare(y) : temp
        return bool
      }

=>

use if (reverse) to create one of two functions before passing to sort, instead of doing same check inside the function. The last one probably is not super beneficial, as smart JIT might specialize it automatically speculatively. Benchmarks required.

Why using a regex to detect sortable class?

e.classList.contains('sortable') ?

I've tested (and this is hilarious with the parentnodes):

if(!b.parentNode.parentNode.parentNode.classList.contains('sortable')){return;}

before the "try" you use, which works fine, this throws out the function instead of running a bunch of stuff unnecessarily. I'd wrap the entire thing in the if statement without the ! probably

Sorted data

I have data that has been pre-sorted on the server before being displayed in the client.

How could I indicate which column the data is already sorted by.

I tried adding the 'dir-u' class to the th, but when the same column is sorted via a mouse click, it ends up with two classes: 'dir-u' and 'dir-d'

FEATURES REQUEST :)

  1. optional column input text filter and still sortable (can be multiple columns having text filter)
  2. optional sticky/fixed table header style
  3. optional table with search bar and pagination ( either top pagination or bottom or both )

Sorting doesn't work in some cases

Good and concise work !
I noticed what could be considered a bug.
Consider the following table:

Field
0
 
0
 
Sorting does not work because (at line 110 of sortable.js) isNaN(x - y) always returns false, since JavaScript interprets an empty string as zero. It could be fixed in several ways (regex, parseInt, trim + test empty string, maybe typeof, ...) This should do the trick: isNaN(parseInt(x) - parseInt(y))

support for colspan attribute in header elements

Would it be possible to support <th colspan=x> in header lines?

I have this minimal HTML example:

<!DOCTYPE html>
<html>
  <head>
    <link href="https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/sortable.min.css" rel="stylesheet" />
    <script src="https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/sortable.min.js"></script>
  </head>
  <body>
    <table class="sortable">
      <thead>
	<tr>
	  <th colspan="2">col 1</th>
	  <th>col 3</th>
	</tr>
      </thead>
      <tbody>
	<tr>
	  <td>a</td><td>bb</td><td>dddd</td>
	</tr>
	<tr>
	  <td>dddd</td><td>dddd</td><td>ccc</td>
	</tr>
	<tr>
	  <td>ccc</td><td>a</td><td>a</td>
	</tr>
	<tr>
	  <td>bb</td><td>ccc</td><td>bb</td>
	</tr>
      </tbody>
    </table>
  </body>
</html>

Sorting by clicking on the "col 3" header actually sorts the table by the second column, not by the 3rd column as expected.
I would guess that the code counts <th> elements and does not look for colspan attributes.

I've come across this probem on my first usage of sortable.
I do have a usable workaround by splitting my <th colspan=2> into 2 separate <th> elements and the table sorts as expected.
So this is no deal-breaker for me, but if it is something that you want to support and perhaps it's not that hard to implement, then I would kindly request this feature :-)

re-sort for changed data

Hi,

I have a table where data flows in over time.
Clicking the header to sort is:

  • A manual action
  • And sorts in the reverse order that it was presented in (by design)

So i'm looking for a way to re-sort the data without clicking the header. Just resort with the current setting (asc or desc).

npm package?

@tofsjonas, thanks for a nifty library!

I'd love to use this as an npm package -- and I believe others would too. If you're open to it, shall I send a pull request for a package.json?

I thought npm install vanilla-sortable might work, since vanilla-sortable is available, and most other variants of sortable aren't. What do you prefer?

Footer click sorts table

When I include a footer in my table, clicking the footer cells sorts the table, even when I add the .no-sort class to them

Header only clickable once

Great code! I am testing the demo in WP and I can only click the headers once (ascending order). Thank you.

Sort icon

This is probably a misunderstanding on my part but the default sort icon points the opposite way to the actual sort direction.

I have tried with and without the 'asc' class:

With asc class added to the table element
image

With asc class removed from the table element
image

Obviously, I could simply change the css to swap the content for dir-d and dir-u but I'd prefer to know what I might be doing incorrectly

sortable.min.js behind

Love the simplicity of the app.

Your min.js file is behind however. I was very confused for a little bit.

Thanks again.

Enhancement request: positioning of sort indicator

The sort indicator is positioned using ::after. Any interest in adding a class to allow it to be optionally positioned ::before as well?

The use case would be for right aligned columns. Currently the ::after adds extra space which results in the header column not lining up with the body columns.

Example: Right alignment issue

image

Example: positioning indicator using ::before

image

Only sorts first tbody tag

Sometimes it is required to group row data. This is usually done using multiple tbody tags.

Sortable only sorts the first tbody, my expectation was it would sort all tbody according to the first tr within each tbody.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.