Monday, 24 August 2009

Row Grouping for YUI Data Table

I've previously harped on about how great the YUI Data Table is so I'll spare the introduction.

For all its bells & whistles, what the data table doesn't offer is grouping of rows - i.e. you're limited to 1 level of data. But thanks to the YUI data table's extensibility, there's plenty of opportunity to roll your own - which is what I did:

Download from GitHub

The YUI data table provides a custom row formatter hook, which allowed me to insert a group header at the relevant points. I had to use a bit of CSS trickery to insert the headers, as they are floating DIV elements, not table rows. The reason for this is that inserting rows caused the YUI data table to get confused if row selection is enabled.

Update 4 Nov 2009: Thanks to the hard work of contributor Mark Mansour many updates have been made to the Grouped Data Table. Mark has made the component inherit from the standard DataTable, plus many other bug fixes & enhancements.

The extension also supports collapsing of groups, and group selection:

Usage is pretty straightforward, firstly include the groupeddatatable.js file on your page:

    <script type="text/javascript" src="groupeddatatable.js"></script>

There is also a set of default styles based on the yui-sam look & feel:

    <link rel="stylesheet" type="text/css" href="assets/datatablegrouper.css">

GroupedDataTable inherits from the standard YUI DataTable, so create an instance of it as per the standard YUI component:

    // Create a GroupedDataTable based on the supplied columns & data source
    var myDataTable = new YAHOO.widget.GroupedDataTable("dtContainer", myColumnDefs, myDataSource, { groupBy: "state" });

Notice the extra groupBy configuration parameter.

That's it. There's a much more detailed example provided with the script.

As always, there's bound to be issues with the script as there are too many scenarios for me to test. So please let me know what you come across.

Cheers, Anthony.

30 comments:

Sergei said...

Man, this is great addon.
You are realy cool.
Thank you

jreader01 said...

Script works great, only problem i had was the width setting doesn't work with yui-2.6's dom-event

Do you have any hooks to collapse/show groups programmaticaly?

Anthony said...

Hi, can you provide more detail on the width problem? I coded against yui 2.7 so not sure if this fixes your problem.

There are no methods for toggling groups at the moment, but I could add them. I'm planning to make some other updates so I'll try and include this in the next release (1-2 weeks).

Cheers,
Anthony

jreader01 said...

Looks like the width problem was a result of Yui-2.6's dom-event class missing the getRegion method. I was able to bypass it by using the offsetWidth of the row. Unfortunately when you use minWidth's in the table, it grows after the setGroupWidth function is called and doesn't stretch. You may be missing an internal resize event.

Also just ran into problems where the height of a row exceeds one line, the group headers don't cover the whole row when they minimize and appear to "eat" rows if you collapse/expand in IE7.

Keep in mind these could all be related to trying to run this in yui-2.6

Neeraj said...

This script is really great. Works like a charm.
Thanks for the script.

Anthony, does this script provides a second level of grouping as well. How can I achieve second level of grouping using this script.

Thanks Again,
Neeraj

Anthony said...

It only supports one level of grouping at the moment. However, I'll add this to the wishlist.

Anthony.

Neeraj Gupta said...

Hi Anthony,

I figured out a slight problem in this solution.
When the width of table (say a single column table) is less then the text width of group then this grouper rows goes out of the table to fit the whole content in one line without any wrapping.

How can I make this text to wrap and fit the grouper width to table width even if the table width is less than the width of the text in group column?

Thanks,
Neeraj

David Chan said...

this is very useful script, one problem I have is sorting will break the grouping, what's best way to allow client side sorting as well keep the good grouping?

David Chan said...

hey, I added these new features:

1. client side group sorting
2. dynamic group change
3. fixed problem when first column is hidden column

let me know if you will like to see the code.

Neeraj said...

Hi Anthony,

Thanks for adding the 2nd level grouping to wishlist. Kindly do let me know once you get a chance to implement that.
Also, I noticed another small problem regarding word wrap of the grouper text. If the data table text has just one column then the grouper row are of varying lengths which move out of data table boundaries. Any hints as where and how shall I introduce word wrap in the script?

Thanks,
Neeraj

TarekAHF said...

Hi,

This is really greate add-on for YUI DataTable.

I was wondering if you have any plans to add the following, or just consider it for impronment:

1. Add ability to summarize numeric fields.

2. Add ability to count number of rows in a group.

4. Allow aggregation per group.

5. Display the totlas per group at the end or in the beginning of the group.

Tarek.

Mike Prince said...

Thanks for this - looks very good.

What is the easiest way to turn off grouping when a column is sorted? Grouping typically only makes sense when sorted on a particular column, so I'd like to turn it off if any other column is used for sorting, and turn it back on if the "primary" sort column is used again.

doBeforeSortColumn will trap the sort, but I'm not sure how to toggle grouping on or off.

jamrsim said...

Great addition to the DataTable widget. Works wonderful for FF 3.5.3. However, my deployment environment is IE7 and I receive an error if I collapse a row grouping, then attempt to expand the same row grouping. I receive javascript error:
Line: 300
Error: Could not get the display property. Invalid argument.

Appreciate any hints on fixing, as I'm new to YUI and js. Thanks.

jamrsim said...

I figured out the IE7 problem. Simply change
row.style.display = "table-row";
to
row.style.display = "";
what would be more elegant is to figure out how YAHOO abstracts this out and possibly leverage that so it could be used for either browser.

Thanks for the cool tool!!

Anthony said...

Hi Neeraj, check out the updates made to the component (re-read the blob post, the code has now moved to GitHub). This problem has been fixed.

Anthony.

Anthony said...

Hi David, thanks for contributing. We've moved the code onto GitHub, so if you would like to Fork and add your enhancements that would be great.

Cheers, Anthony.

Anthony said...

Hi Tarek. Thanks for the suggestions, however I have no plans to add this functionality.

If you would like to have a stab at adding this yourself then please feel free to Fork the source on GitHub.

Cheers,
Anthony.

Anthony said...

Hi Mike, thanks for your feedback. I agree this would be a good feature, but I'm a little strapped for time at the moment.

I guess a quick solution would be to disable sorting altogether. Alternatively if you would like to have a stab at adding this, you can fork the source on GitHub.

I'll add it to the wishlist for the coming months.


Anthony.

Anthony said...

Hi jamrsim, check out the updates on GitHub - many bug fixes have been made.

Anthony.

jamrsim said...

From an IE7 perspective, the prior version appears to function better. From Firefox, yes, it looks to be much better and I like the fact that it is now an extension of DataTable. Thanks for all the effort.

David Chan said...

Anthony, I just did a fork with my code, but my changes are base on old version, the changes I added:
1. group sorting (column sorting is within same group only)
2. change group by demo

Anthony said...

Thanks David, I'll take a look.

Anthony.

Ernesto said...

Hi!
There is Etx JS Grouping, Summary and Totals implementations, to get ideas

http://www.extjs.com/deploy/dev/examples/grid/grouping.html

http://www.extjs.com/deploy/dev/examples/grid/totals-hybrid.html

Greets,
Er

Lukka said...

Hey, thank you for this addon. I haven't tried it yet, but looks like it will be a great solution to my problem.

Paul said...

Hi,

This is a very nice component, thanks to Anthony and Mark (and other contributers) for the hard work.

Any thoughts on how to get this to work with a ScrollingDataTable? I tried extending ScrollingDataTable instead of DataTable but it didn't work out quite right.

My table is long enough to benefit from both scrollbars and row grouping, so if anyone has any thoughts on this I'd like to hear them.

Thanks,

Paul

Alpha0 said...

We have placed a button in the row on click of which we access the current row data and open a new window based on the data in the current row.

But after we have added grouping to this table, we always get the row which wrong (offset by number of groups which are above the current row).

Let me know if there is a quick fix to it.

Regards,
Alpha0

Anthony said...

How are you getting a reference to the row?

Alpha0 said...

Here is the code snippet:
this.myDataTable.subscribe("buttonClickEvent", function(oArgs){
var oRecord = this.getRecord(oArgs.target);
var column = this.getColumn(oArgs.target);
if (column.key == "view"){
var report_abs_url = oRecord.getData("url")
window.open(report_abs_url);
}
});
}

fraparisi said...

Is possible to use this to do grouping with a column that exist? thanks!

Kelly said...

Great addon! Couple minor things I'd like to point out..

1) to add ScrollingDataTable support
a) the css for .icon div must not be absolute
b) replace groupCell.setAttribute("colspan", numberOfColumns); with groupCell.colSpan = numberOfColumns;
c) Replace YAHOO.widget.DataTable with YAHOO.widget.ScrollingDataTable

2) I did notice one small bug with drag & drop of columns (reordering). I had to extend the reorderColumn method & add code for it to skip the TR rows that had class of "group".

Otherwise great addon.. Thanks!