Quick follow-up. It does appear to be important that a dynamic column have a valid dataField property, even though it has a labelFunction to actually determine the displayed value. I ran into a situation where the little triangle was jumping from the currently sorted column to the first column when the data source was refreshed, without actually sorting that column.
I'm not sure why this was not an issue in the little test case I posted a couple of messages ago, and I'm also not sure what one should do when there are two dynamic columns derived from the same underlying property. But I thought I'd mention this, as it solved one problem I was seeing. On Fri, Feb 12, 2010 at 11:22 PM, Richard Rodseth <rrods...@gmail.com>wrote: > Lots of crossed wires here. Sorry I wasn't more clear. > > My last two messages were the solution for the benefit of others, not > further puzzlement. > Yes the test case I included runs perfectly, as I said. > Yes, a specified dataField must exist. The code I inherited had both a > non-existent dataField named, and a dynamic label function, for the same > column. I had missed this when I first posted the question and it was the > cause of the error, which only manifested itself when clicking on the column > header. > > Thank for the other suggestions. Using creationComplete was just for the > test case. It seems to me that the appropriate place to set the initial > default sort object is when the array collection is created (which I would > generally have in a presentation model). Then the array collection just > sticks around and when new data is fetched from the server (this UI is a > search view) it is just placed in the source of the array collection and the > grid is automatically sorted by whatever the current sort is (either the > initial one, or whatever column has been clicked subsequently). As the test > case showed, this could be achieved without calling sort methods or refresh > explicitly. > > As for the two compare functions, this was to make the initial sort > descending but still have the column clicking work. It sounds as though you > have a preference for calling the sort() method explicitly with the > DESCENDING argument. I don't know if the sort persists in that case. > > Given the requirement of a default initial sort, but preservation of > subsequent user-initiated sorts, the test case approach seems pretty good to > me. > > > On Fri, Feb 12, 2010 at 10:30 PM, Alex Harui <aha...@adobe.com> wrote: > >> >> >> I doubt that would be true unless the dataField was didn’t exist as a >> top-level property in the data objects. I ran your test case and never got >> any error. >> >> Looking at the code, I don’t know why you need two sort functions. They >> look the same. Also, I would apply the sort after setting the source and >> call refresh() instead of setting the sort up on creationComplete. If you >> want, you could listen for a collectionEvent with CollectionEventKind.RESET >> and apply the sort then. >> >> >> >> On 2/12/10 4:47 PM, "Richard Rodseth" <rrods...@gmail.com> wrote: >> >> >> >> >> >> >> And it appears the error *was* caused by having a column with a value for >> both labelFunction and dataField. >> >> On Fri, Feb 12, 2010 at 3:36 PM, Richard Rodseth <rrods...@gmail.com> >> wrote: >> >> Original question: >> >> >> Is there a recipe for sorting initially on a column which has a computed >> value in it? >> >> I put together the example below which works great. I'm not sure what's >> triggering the error in the actual code I'm dealing with, but this example >> convinces me it's time for some refactoring. >> >> <?xml version="1.0" encoding="utf-8"?> >> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >> layout="vertical" >> creationComplete="onCreationComplete(event)" >> > >> >> <mx:Script> >> <![CDATA[ >> import mx.controls.dataGridClasses.DataGridColumn; >> import mx.controls.advancedDataGridClasses.SortInfo; >> import mx.collections.SortField; >> import mx.collections.Sort; >> import mx.collections.ArrayCollection; >> >> private function onCreationComplete(event:Event):void { >> var sortByNameLengthDescending:Sort = new Sort(); >> sortByNameLengthDescending.compareFunction = >> nameLengthDescendingCompareFunction; >> this.devices.sort = sortByNameLengthDescending; >> } >> >> private function onRefresh(event:Event):void { >> var items:Array = [ { name:"AName", value:Math.random() }, >> >> { name:"BName", value:Math.random() }, >> >> { name:"CName", value:Math.random() }, >> { name:"ANameLong", >> value:Math.random() }, >> { name:"BNameLonger", >> value:Math.random() }, >> { name:"CNameLongest", >> value:Math.random() } >> ]; >> devices.source = items; >> } >> >> private function onClear(event:Event):void { >> devices.source = []; >> } >> >> private function countSquared(item:Object, >> column:DataGridColumn):String { >> var value:Number = item.count * item.count; >> return value.toString(); >> } >> >> private function nameLength(item:Object):int { >> var name:String = item.name <http://item.name> ; >> >> return name.length; >> } >> >> private function formattedValue(item:Object, >> column:DataGridColumn):String { >> return item.value.toFixed(3); >> } >> >> private function nameLengthLabelFunction(item:Object, >> column:DataGridColumn):String { >> var nameLength:Number = nameLength(item); >> return nameLength.toString(); >> } >> >> private function nameLengthDescendingCompareFunction(a:Object, >> b:Object, fields:Array = null):int { >> var length1:int = nameLength(a); >> var length2:int = nameLength(b); >> if (length1 == length2) >> return 0; >> else if (length1 < length2) >> return 1; >> else >> return -1; >> } >> >> private function nameLengthCompareFunction(a:Object, b:Object, >> fields:Array = null):int { >> var length1:int = nameLength(a); >> var length2:int = nameLength(b); >> if (length1 == length2) >> return 0; >> else if (length1 < length2) >> return -1; >> else >> return 1; >> } >> >> [Bindable] >> private var devices:ArrayCollection = new ArrayCollection(); >> >> ]]> >> </mx:Script> >> >> >> <mx:DataGrid dataProvider="{this.devices}"> >> <mx:columns> >> <mx:DataGridColumn headerText="Name" dataField="name"/> >> <mx:DataGridColumn headerText="Value" dataField="value" >> labelFunction="formattedValue"/> >> <mx:DataGridColumn headerText="NameLength" >> labelFunction="nameLengthLabelFunction" >> sortCompareFunction="nameLengthCompareFunction"/> >> </mx:columns> >> </mx:DataGrid> >> >> <mx:HBox> >> <mx:Button label="Fill" click="onRefresh(event)"/> >> <mx:Button label="Clear" click="onClear(event)"/> >> </mx:HBox> >> >> </mx:Application> >> >> >> >> >> >> >> >> On Fri, Feb 12, 2010 at 2:12 PM, Alex Harui <aha...@adobe.com> wrote: >> >> >> >> >> >> >> You should always specify a valid dataField. >> >> If you have null data items or items that are dynamic and missing >> properties you can hit this error. >> >> >> >> On 2/12/10 11:35 AM, "Richard Rodseth" <rrods...@gmail.com < >> http://rrods...@gmail.com> > wrote: >> >> >> >> >> >> >> Yes, it's in an override of set dataprovider which calls super (I would >> not have done things this way). >> >> And it does sort correctly initially. It's only when I click on the column >> that I get the error. >> >> One thing I'm asking myself is if it's harmful or just redundant to >> specifiy dataField if you are specifying a labelFunction and >> sortCompareFunction. >> >> On Thu, Feb 11, 2010 at 11:52 PM, Alex Harui <aha...@adobe.com < >> http://aha...@adobe.com> > wrote: >> >> >> >> >> >> >> I also noticed your code snippet did not call refresh() >> >> >> >> On 2/11/10 9:32 PM, "Richard Rodseth" <rrods...@gmail.com < >> http://rrods...@gmail.com> <http://rrods...@gmail.com> > wrote: >> >> >> >> >> >> >> It is. >> >> Sent from my iPhone >> >> On Feb 11, 2010, at 9:30 PM, Alex Harui <aha...@adobe.com < >> http://aha...@adobe.com> <http://aha...@adobe.com> > wrote: >> >> >> >> >> Also assign the sortCompareFunction to the column. >> >> >> On 2/11/10 5:07 PM, "Richard Rodseth" <rrods...@gmail.com < >> http://rrods...@gmail.com> <http://rrods...@gmail.com> > wrote: >> >> >> >> >> >> >> I'm thoroughly confused by the DataGrid sorting stuff. >> Is there a recipe for sorting initially on a column which has a computed >> value in it? >> >> Some code I inherited is doing this by overriding the dataprovider setter >> and calling >> >> if (sortEventCounts && value is ArrayCollection && >> configuration.eventCount) { >> ArrayCollection(value).source.sort(eventCountSort, >> Array.DESCENDING); >> >> ArrayCollection(value).addEventListener(CollectionEvent.COLLECTION_CHANGE, >> function (event:Event=null):void { >> ArrayCollection(value).source.sort(eventCountSort, >> Array.DESCENDING); >> }); >> } >> >> Possibly unrelated to the above, but when I make some other (computed) >> columns sortable (with associated compare functions), I get the dreaded >> "Find criteria must contain at least one sort field value" when I click on >> the event count column affected by the above. Removing the explicit sort >> above gets rid of this error. >> >> The documentation talks about creating a Sort() object and assigning it to >> the ArrayCollection's sort property, but when I tried that (setting its >> compare function rather than the fields array) instead of the above, the >> column did sort initially, but I still got the error on clicking the column. >> >> >> Any pointers? >> >> >> >> >> >> >> -- >> Alex Harui >> Flex SDK Team >> Adobe System, Inc. >> http://blogs.adobe.com/aharui >> >> > >