Sorting and the DataGrid component
Another Tuesday LiveDocs day! The following example continues the theme of DataGrids and sorting.
The following example sorts columns either numerically or alphabetically. By default columns are sorted alphanumerically, so if you had a DataGrid with "1, 213, 11, 7" it would sort as "1,11,213,7". By writing a custom sorting function that uses Array.sortOn, you can sort the dataProvider yourself using a numeric or text sort (even sort text as case insensitive).
1. Make sure you have DataGrid in Library
2. Add following ActionScript to frame 1 of the Timeline:
import mx.controls.gridclasses.DataGridColumn;
var my_dp:Array = new Array({name:'Grissom, M.', avg:0.279}, {name:'Bonds, B.', avg:0.362}, {name:'Cruz, D.', avg:0.292}, {name:'Snow, J.', avg:0.327});
var dg = this.createClassObject(mx.controls.DataGrid, "my_dg", 999, {dataProvider:my_dp});
dg.setSize(240, 180);
var name_dgc:DataGridColumn = new DataGridColumn("name");
name_dgc.headerText = "Name:";
name_dgc.width = 160;
dg.addColumn(name_dgc);
var avg_dgc:DataGridColumn = new DataGridColumn("avg");
avg_dgc.headerText = "Avg:";
avg_dgc.width = 60;
dg.addColumn(avg_dgc);
//
var myListener:Object = new Object();
myListener.headerRelease = function(evt:Object) {
var sortOrder:String = evt.target.sortDirection;
var sortColumn:String = evt.target.columnNames[evt.columnIndex];
switch (sortColumn) {
case 'name' :
sortArray(my_dp, sortColumn, "TEXTNOCASE", sortOrder);
break;
case 'avg' :
sortArray(my_dp, sortColumn, "NUMERIC", sortOrder);
break;
}
};
my_dg.addEventListener("headerRelease", myListener);
//
function sortArray(my_array:Array, sortColumn:String, sortType:String, sortOrder:String) {
var sortOptions:Number = 0;
switch (sortType.toUpperCase()) {
case 'NUMERIC' :
sortOptions |= Array.NUMERIC;
break;
case 'TEXTNOCASE' :
sortOptions |= Array.CASEINSENSITIVE;
break;
}
if (sortOrder.toUpperCase() == 'DESC') {
sortOptions |= Array.DESCENDING;
}
my_array.sortOn(sortColumn, sortOptions);
}
3. Format the code (press the Auto Format button).
4. Test.
Comments
Hey Jen,
How do you preselect a row in a Datagrid, from previously entered data or from another object?
Posted by: Micah Douglas | December 14, 2004 12:45 PM
That wasn't very clear.. I am sorry.
What I meant was that I have some data in a datagrid that I want to have one of the rows preselected.
Wait.. Maybe a drop-down combo box would be better..
Thanks.
Micah
Posted by: Micah Douglas | December 14, 2004 12:47 PM
Hi Micah,
Try this:
my_dg.dataProvider = [{num:1}, {num:213}, {num:11}, {num:7}];
my_dg.selectedIndex = 1;
This code preselects the second row in the DataGrid (0 based, so the second row).If you want to pre-select multiple rows, you have to make sure that the multipleSelection property is set to true first.
my_dg.dataProvider = [{num:1}, {num:213}, {num:11}, {num:7}];
my_dg.multipleSelection = true;
my_dg.selectedIndices = [1, 2];
Hope that helps,
Jen.
Posted by: jdehaan | December 14, 2004 01:10 PM
How about preselecting based on one of the VALUES in that list. I am having trouble getting that accomplished.
Thanks mucho appreociated.
Micah
Posted by: Micah | December 14, 2004 02:20 PM
Sure -- the following selects rows based on a value in the DataGrid.
my_dg.dataProvider = [{num:1}, {num:210}, {num:11}, {num:7}];
my_dg.multipleSelection = true;
my_dg.selectedIndices = selectOddNumbers();
function selectOddNumbers():Array {
var temp_array:Array = my_dg.dataProvider;
var return_array:Array = new Array();
for (var i = 0; i
Posted by: jdehaan | December 14, 2004 03:27 PM
Nice example! That sortDirection property really should have been public to start with. It's worth pointing out that this example makes the correct choice in using Array.sortOn rather than Array.sort (and a comparison function) - Array.sortOn is an order of magnitude faster than using that comparison function. It's kind of why we didn't offer a dGcolumn.sortFunction property per column, to avoid people trying. It would have maybe made more sense to add a sortOptions property for the column instead. Oh well.
Posted by: nig | December 14, 2004 04:00 PM
I really wish that there was a way to easily define whether a column is text or numeric. I figure there has to be a simpler way to sort columns than the method listed above (no offense, jan).
Or if not, any chance that somebody at MM can add that in the next version? (crosses fingers)
Posted by: peter | December 14, 2004 05:24 PM
I guess the sort by number will work for a date field as well in that a date is really a number.
Correct?
Posted by: cvb | December 15, 2004 05:51 AM
Hi jen, maybe this is not the right place to write this but...about your Data for Designers: Connecting to Data in Flash Using Data Wizards: I worked with your samples it works great..however when I put the datagrid component and the xml connector in a movie I can not see my data from the xml?
I hope you can answer me
Posted by: czeren | December 23, 2004 03:13 AM
Hi Jen - I tried your sorting code with my dataprovider (created from an array) and datagrid, but the columns still sort incorrectly, ie 78 comes after 120 etc
help!
regards
frank
Posted by: frank bradshaw | January 13, 2005 02:35 AM
Hi again - your code works fine; but this is my code: function fillMebersGrid(records:String):Void {
var tempRecords:Array = new Array();
tempRecords = records.split(rowDelimiter);
for (var i = 0; i var tempArr:Array = new Array();
var tempObj:Object = new Object();
tempArr = tempRecords[i].split(fieldDelimiter);
for (var j = 0; j tempObj[tableFields[j]] = tempArr[j];
}
myDataprovider.push(tempObj);
}
members_dg.dataProvider = myDataprovider;
}
myDataprovider is still an array here, so in theory your code should work with mine....
any thoughts or suggestions?
cheers
frank
Posted by: frank bradshaw | January 13, 2005 07:03 AM
1 month on so not sure if anyone cares, i had the same problem is frank above. The functions (correct values passed etc) were working but the grid still wasnt being sorted properley.
Im thinking the problem was related to the way the grid is being dynamically populated.
I changed:
my_dp.push(rowObj);
to:
my_dp.addItem(rowObj);
And any column that was numeric i used the Number() function when adding to the rowObj.
Quirky little solution but it worked!
Posted by: Zac | February 13, 2005 02:56 PM
I added a line to make the datagrid ediable:
dg.editable = true;
After that, the sorting doesn't work right anymore. Numbers are sorted like strings.
How can I contact jdehaan?
Posted by: alfred | February 14, 2005 08:16 PM
Alfred, where did you put that line of code? I used the code directly from this page and set the "dg.editable = true;" on line 5 (but anything after line 3 should work) and it worked like a charm.
Posted by: peter | February 14, 2005 10:41 PM
I place it below line 5. Even now that I've moved it to line 5, it doesn't work once I type my own values.
I'm using the FIRST example code on top, and nothing else.
Try this:
Avg:
520
5100
101
12
The sorting isn't right. Can you please check?
Running on FlashMX 2004 ver 7.2
Posted by: alfred | February 15, 2005 05:45 AM
Alfred, yeah, that seems very weird. The batting averages are numbers, yet, after they've been edited, they seemingly change to string datatypes (which I guess makes sense, but is still buggy since you'd expect a numeric sort to try to convert it back to numbers).
I added this code to the sortArray function (right above the my_array.sortOn(...) bit):
var i:Number;
for (i=0 ;i<my_array.length; i++ ) {
trace(i+": "+typeof(my_array[i][sortColumn]));
}
If you test your Flash document in the authoring environment, you should see 0..3 are all numbers. Now, change 101 to 1010 and it should be a mix of numbers and strings. I'm guessing you'll have to modify the code to convert from strings back to numbers. Not sure of the most efficient way, but seemingly the following code works:
function sortArray(my_array:Array, sortColumn:String, sortType:String, sortOrder:String) {
var sortOptions:Number = 0;
switch (sortType.toUpperCase()) {
case 'NUMERIC' :
var i:Number;
for (i=0; i<my_array.length; i++) {
my_array[i][sortColumn] = Number(my_array[i][sortColumn]);
}
sortOptions |= Array.NUMERIC;
break;
case 'TEXTNOCASE' :
...
Posted by: peter | February 15, 2005 10:44 AM
Actually, this is another cool little trick (and probably a lot more efficient than my attempt at re-casting every row of the DataGrid to the Number data type.
You could create an event listener for the "cellEdit" event, which just casts the changed cell from the String back to a Number.
Code ahoy! Add this code around line 15 or something, or anywhere around the headerRelease event listener code:
// ----------
myListener.cellEdit = function(evt:Object) {
var columnName:String = evt.target.columnNames[evt.columnIndex];
var cell:Object = evt.target.dataProvider[evt.itemIndex];
switch (columnName.toLowerCase()) {
case 'avg':
cell[columnName] = Number(cell[columnName]);
break;
}
}
my_dg.addEventListener("cellEdit", myListener);
// ----------
HTH
peter
Posted by: peter | February 15, 2005 11:05 AM
Thanks Peter. Working fine now. Big THANKS!!!
I can't believe how hard it is to make numbers sort correctly....spent days figuring out and searching for answers. This tutorial is very possibly the ONLY number sorting tutorial on the INTERNET that actually works!
Peter, is it possible for u to send me a e-mail?
I'm actually trying to make a simple scoreboard that sorts score from highest to lowest... still have a bit more to do.... my first attempt at DataGrids/Arrays.
If you can help, I'll explain what I need. Should be very easy for you.
Thanks
Alf
Posted by: alfred | February 15, 2005 12:25 PM
Some things I can't figure out:
1) How can I make a button sort the avg cloume (always descening?) Instead of using the "headerRelease".
2) How to get a list of all the datagrid entries?
eg. trace(my_array.join()); shows me [object Object],[object Object],....
Thanks
Posted by: alfred | February 21, 2005 10:24 AM
Thanks!
Was having headaches trying to cast my to numbers and sorting by this did the trick.. thanks for sharing!
Posted by: Mike | April 10, 2005 04:35 PM
What do I need to do to create a primary and secondary sort key? e.g. first sort on Country then within that sort on Age
Posted by: necoqij | October 19, 2005 07:19 AM
all your codes sort the arrays, alryt. do it in this way - each column taking data from different arrays (or an XML) and the numeric columns need to be sorted. if i put your code, i will get the arrays sorted, but the datagrid is not updated. by tracing we can c the arrays are sorted numerically. its not reflected in the datagrid. is there any function to update datagrid to be called? plz do help..
thank you.
Posted by: aneeshanand | May 4, 2006 10:11 PM