joequery/Stupid-Table-Plugin

Be able to sort programmatically

Closed this issue · 38 comments

I'd love a way to call the sorting as needed (without a click).

Is this possible/easy to do?

Currently you can just call .click() on the th associated with the column you want sort. So, for example,

$("#some_element").on("mouseenter", function(){
    $("#my_table th").eq(1).click();
});

I can't do that because the data changes, so I need to resort the entire table. If I just call click, the sort reverses.

Ah, I see. The sort needs to be friendlier for dynamic tables.

Ya, I want to be able to call table.sortNow() or something like that.

If you can give some guidance, perhaps I can make it work and submit a pull request?

We can probably move the sorting logic to a function like

$("#my_table th").eq(1).stupidsort('asc')

And just have

$("#mytable").stupidtable()

be in charge of binding the table's th to call stupidsort on click. That way you can manually call sort if you wish. Shouldn't be that difficult of a change.

ya, that's exactly what I want.

Check out this branch.

https://github.com/joequery/Stupid-Table-Plugin/tree/stupidsort

With the changes, current unit tests are passing, but I didn't have time to create new tests for the stupidsort method.

$("#mytable").stupidtable()

Will work as usual. This must be called first before you're allowed to call .stupidsort().

Now you can select a th and call .stupidsort().

$("#mytable thead th").eq(0).stupidsort('asc');
$("#mytable thead th").eq(0).stupidsort('desc');

If you don't provide the direction argument, it will just change directions.

Once I get some unittests written I'll merge into master.

Please disregard my previous (now deleted) comment.

This works perfectly for me, marking closed.

Thanks a ton!

Thanks for the issue and the quick feedback.

I made a fiddle here as a demo before I get around to merging this into master and updating the official docs:

http://jsfiddle.net/JoeQuery/bc79Ltos/11/

I'm going to go ahead and reopen this issue and leave it open until the merge is complete. Thanks again @edalzell , and to the all the other people who have requested this feature.

Here are some thoughts

I really don't want people to have to call a selector for a th just to sort. I think we should try to accomplish this from the table itself.

I have two ideas on how to accomplish this:

  1. allow the data-sort attribute on the th to optionally be of the form "label:data-type", so something like
<th data-sort="first_name:string">First Name</th>

And then the call would look like

var $table = $("#mytable").stupidtable();
$table.stupidsort('first_name', 'desc');

This wouldn't introduce backwards compatibility issues. These labels can be optional - we just check for the existence of the colon

  1. We just add a data-sort-label attribute. We already have a lot of data attributes being used, so I'd like to avoid introducing another one.
<th data-sort="string" data-sort-label="first_name">First Name</th>

@svivian @jefflunt @tag your thoughts?

tag commented

Well, since you asked ...

Object attributes should do one thing only IMHO, thus, I would prefer the second of your two suggestions.

Haven't tested it out, but the current sort direction is stored in the table's sort-fir data, so re-sorting with the existing sort is something like

$('#mytable thead th').eq(0).stupidsort('myThLabel', $('#mytable').data('sort-dir') || 'asc');

... right? Seems a bit awkward.

$('#mytable').stupidsort('myThLabel')

Would be all that's needed to either initially sort or reverse the sort of that column. That .data call would occur within the plugin definition, no need to make that part of the call on the user end. We could allow for the first param to be a string (label) or int (index), that way the labels remain optional.

tag commented

Was talking about a re-sort of dynamic tables.

On Sep 24, 2014, at 10:14 AM, Joseph McCullough notifications@github.com wrote:

$('#mytable").stupidsort('myThLabel')
Would be all that's needed to either initially sort or reverse the sort of that column. That .data call would occur within the plugin definition, no need to make that part of the call on the user end. We could allow for the first param to be a string (label) or int (index), that way the labels remain optional.


Reply to this email directly or view it on GitHub.

The fiddle I linked (http://jsfiddle.net/JoeQuery/bc79Ltos/11/) already has a working implementation, but it requires a th selector. The stupidsort call itself is already taken care of. It's just a matter of whether it should be called on the th or the table.

tag commented

Right. The important line of code was

$("#relevant").stupidsort('asc') 

... but what if the table needed to be resorted on that column, but the currently applied sort (asc or desc) was not known? (Which was the point I was trying to make.)

tag commented

Also, inspired by your fiddle, I don't think the data-sort-label is necessary, because a DOM node (or column index, or jQuery object, etc.) could be passed instead. data-sort-label duplicates information available via other means.

I think it's perfect the way it is. Select the column, then sort it.

Thanks for the feedback. I'll think about this a bit more. :)

Sorry it doesn't work. Here's what I do:

  1. display the table
  2. based on what the user types, I show/hide various rows. I also add a 'relevance' number in the last col.
  3. after I do a show/hide, I always want to sort by relevance in desc order

So I do my show/hiding and then call $('#relevance').stupidsort('desc'); where my last column has an id of 'relevance'.

It doesn't not sort.

Ideas? Or how can I help you debug?

Even when I click the header to manually sort, it doesn't work properly. Are you storing or caching the data-sort-values? How can I refresh them after if that is the case?

Can you create a fiddle recreating the problem? Thanks

I'm new to jsfiddle. How do I include your stupidtable js?

I am having trouble getting the reduced case to even run.

I have this: http://jsfiddle.net/edalzell/1ddwh0xu/ but the .lastChild call does not return the last column for some strange reason.

Apologies, I am not a great JS programmer so have difficulty getting this going.

Use item.lastElementChild instead of item.lastChild. .lastChild includes textnodes, so what's happening is that the whitespace in the tr is being selected. .lastElementChild restricts the traversal to only element results.

AHA, I managed to duplicate it!

Check my jsFiddle: http://jsfiddle.net/edalzell/1ddwh0xu/4/

First time it runs, it sorts fine. Then press the 'set' button and you'll see the values are NOT sorted.

Hi @joequery, can you let me know if this is something you will be looking at? If you don't have time or it's not relevant, that's fine, I'll go find another solution, no big deal.

Thanks.

Observing the console log data, it seems like the plugin is holding on to stale data internally. It's sorting by the old data internally (and that sort is correct), but we need to make it grab the new table data.

http://jsfiddle.net/JoeQuery/1ddwh0xu/5/

I have to run for now, I'll check this out later.

Looking at this now, I hope to have a solution soon.

Please let me say that your responsiveness has been amazing. I won't hesitate to recommend your software to everyone.

I figured out the problem.

It's actually the fact that jQuery's .data() only initially reads from the html data attributes.

See here: http://stackoverflow.com/a/18107213/670823

So the fix is to use the .data() method to update the sort value instead of updating the html attribute.

http://jsfiddle.net/JoeQuery/1ddwh0xu/6/

Well to maintain visual consistency, perhaps you can update the HTML attribute AND the .data value.

That's a good point. No one likes surprises ;)

OK, so your code works fine if I add

            $(cell).data('sort-value', relevance);

To my code. You should merge in your change and update the docs.

Nice!

👍

So one reason to use .data() over .attr() is that .data() allows you to store objects of an arbitrary type. However, the data-sort-value attribute will always be a string, and .attr() always returns a string. And, as we experienced, using .data() on the tds leads to data being out of sync if people update the data attribute directly. The idea of the markup not reflecting the internal data stored without an explicit call to .data() bothers me a bit.

So I'm considering changing this line

var sort_val = $e.data("sort-value");

to

var sort_val = $e.attr("data-sort-value");

But then will people know to not use .data() to update the values? Is there some way we can watch out for both? I'm not sure. And what about the other settings we're storing in data attributes?

Or does the documentation just need to explicitly say "If you're updating the data-sort-value on a table cell, you must use jquery's .data() method to do so"

I see, you are thinking of NOT using the .data at all?

I don't think it matters much as long as the documentation and examples are clear.

Closed in #136