Complex DataGrid filterFunction in Flex/Air
So I need to add robust user controlled filtering options in the application I am working on. This problem has dogged me for a month or two, with my co-workers politely insisting on more and better ways to filter their data. This is completely understandable. When you are staring down a datagrid that is virtually 12 feet long, getting to what you actually want to see is important.
This 2006 article from Bruce Phillips was a big help in the basic concept of multiple input filtering. As is his normal style, it is littered with good references to the source material from his research. This is only considering two filter parameters, however, and I need to consider n parameters, that will probably shift as the needs of the end user grow.
The problem is that each new filtering parameter exponentially increases the complexity of the filterFunction. I can see the pattern, but I haven't quite reached the epiphany that I need to break it down into one of those tight little functions I see real programmers creating (unfortunately, I haven't seen any that address my specific problem).
I thought I'd share my naive, and perhaps confusing filterFunction. It would be great to hear how others approach this problem, and come up with a concise solution.
This function utilizes a TextInput to get text search input from the user. It uses
a series of CheckBoxes for various status condition to generate an array [ 1, 0, 1, 1 ]
to represent their on/off state. It also uses two combo boxes to filter by staff members
as well as clients.
filterFunction:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | private function filterCases(item:CaseVO):Boolean { //is the item visible or hidden var result:Boolean = false; //array of CheckBox.selected property values // in handy ones and zeroes. This is returned from a function // that takes the actual CheckBoxes as input and gives me this. var case_mask:Array = [ 1, 0, 1, 1 ]; //a couple VOs to verify the selectedItem in the ComboBoxes. var client:PersonVO; var expert:PersonVO; //array iteration variable var i:int; var dateFormat:DateFormatter = new DateFormatter( ) dateFormat.formatString = 'MM/DD/YY' //text search if ( caseGrid.filter.caseNumInput.text.length > 0 ) { var searchResult:Boolean = ( ( String( '0' + item.case_id.toString() ).search( caseGrid.filter.caseNumInput.text ) >= 0 ) || ( item.style.toLowerCase().search( caseGrid.filter.caseNumInput.text.toLowerCase() ) >= 0 ) ); if( item.description ) { searchResult = searchResult || ( item.description.toLowerCase().search( caseGrid.filter.caseNumInput.text.toLowerCase() ) >= 0 ) } if ( item.client_id ) { searchResult = searchResult || ( personProxy.personFromId( item.client_id ).fullName.toLowerCase().search( caseGrid.filter.caseNumInput.text.toLowerCase() ) >= 0 ) } if ( item.date_of_accident ) { searchResult = searchResult || ( dateFormat.format(item.date_of_accident).search( caseGrid.filter.caseNumInput.text ) >= 0 ) } for ( i = 0; i < case_mask.length; i++ ) { if ( caseGrid.filter.client.selectedItem is PersonVO ) { client = caseGrid.filter.client.selectedItem //is an expert selected for filtering also? if ( caseGrid.filter.expert.selectedItem is PersonVO && searchResult) { expert = caseGrid.filter.expert.selectedItem; //filter for client, expert, and status if ( (case_mask[i] && item.status == String( i + 1 ) ) && item.client_id == client.id && item.expert_id == expert.id && searchResult ) result = true; } else { //filter for client and status if ( (case_mask[i] && item.status == String( i + 1 ) ) && item.client_id == client.id && searchResult ) result = true; } } else if ( caseGrid.filter.expert.selectedItem is PersonVO ) { expert = caseGrid.filter.expert.selectedItem; for ( i = 0; i < case_mask.length; i++ ) { //filter for expert and status if ( (case_mask[i] && item.status == String( i + 1 ) ) && item.expert_id == expert.id && searchResult ) result = true } } else { //filter for client and status if ( (case_mask[i] && item.status == String( i + 1 ) ) && searchResult ) result = true; } } } //see if a client is selected for filtering else if ( caseGrid.filter.client.selectedItem is PersonVO ) { client = caseGrid.filter.client.selectedItem for ( i = 0; i < case_mask.length; i++ ) { //is an expert selected for filtering also? if ( caseGrid.filter.expert.selectedItem is PersonVO ) { expert = caseGrid.filter.expert.selectedItem; //filter for client, expert, and status if ( (case_mask[i] && item.status == String( i + 1 ) ) && item.client_id == client.id && item.expert_id == expert.id ) result = true; } else { //filter for client and status if ( (case_mask[i] && item.status == String( i + 1 ) ) && item.client_id == client.id ) result = true; } } } //client isn't selected, check the expert filter. else if ( caseGrid.filter.expert.selectedItem is PersonVO ) { expert = caseGrid.filter.expert.selectedItem; for ( i = 0; i < case_mask.length; i++ ) { //filter for expert and status if ( (case_mask[i] && item.status == String( i + 1 ) ) && item.expert_id == expert.id ) result = true } } //finally, filter for the status else { for ( i = 0; i < case_mask.length; i++ ) { //filter for status if ( case_mask[i] && item.status == String( i + 1 ) ) result = true; } } return result } |
You can see that I am repeating myself from the top down to the final else statement, cutting the filter parameters down like a layer cake. It works, and is relatively quick on a grid with 1500 or so items. This just screams "REFACTOR ME" every time I see it.
VEsession – Flex photography studio management and client ordering application
My wife saw the application that I am working on at work to manage tasks and immediately asked, "Where's mine?"
21st century honey-do list.
So far, this is what I have created. PureMVC is the underlying framework. The photos are loaded from SlideShowPro Director XML galleries. Unforutately, the most recent version of SSP-D won't let you use it as a service in this way. This older version is has all the functionality I need though, so it isn't an issue. Eventually I will implement functionality to eliminate the need for SSP-D with some gallery management. It will be better to keep it all under one roof.
The backend is Django using pyAMF for communications back and forth. Django elminates the pain of CRUD operations and provides an excellent admin interface for free.
My goal is to open source the application and provide it as a PureMVC/Django example.
UPDATED: This version is a little jacked because I am working on a new version. The demo images are way too big and cause the application to scroll in unsightly ways. The new demo is located here, and uses the same credentials as below.
[Here is the demo]
user: demo_client
pass:demo_client

[source]
Do to some, uh, laziness on my part, this will only compile with strict mode turned off The new version does not have this problem.
Flex – Preventing DataGrid scrolling when the dataprovider is updated.
I was having issues with my DataGrid scrolling to the top when my grid updated from the server. It is very aggravating as a user when you are milling about and *BAM* it scrolls away.
This worked:
1 2 3 4 5 6 | var storeItemForUpdate:ItemVO = grid.selectedItem;; var vScroll:int = grid.verticalScrollPosition; arrayCollection.source = updatedDataArray grid.validateNow(); grid.verticalScrollPosition = vScroll; grid.selectedItem = storeItemForUpdate; |
The current selection is stored, the scroll position is stored, the grid is updated, validated, and then the stored variables are applied without so much as a flicker on the screen for the user. Much better.
FlexUnit – Some useful examples and tutorials covering unit testing in Flex and Actionscript 3.0
In an effort to build my skills and create applications that are based on a firm foundation, I am implementing unit testing. So far I am completely sold on the concept, and while I'm not quite to the point of full TDD, I can see the benefits immediately with the tighter code and confidence level that accompanies it. Here are some of the useful resources that I came across in my research. They are all centered around FlexUnit, the 'official' unit testing framework for Actionscript 3.
Neil Webb has an article on Adobe's Developer Center that covers the basics of getting started with FlexUnit. It is thorough and easy to read. This is probably the best starting off point that I have come across
Theo Hultberg has some valid critiques of the framework, as well as an alternative approach to the 'Temperature Conversion' example that is supplied with the FlexUnit distribution. I found this to be extremely helpful in deciphering FlexUnit and getting it up and running in my project.
Eric Feminella has created a simple API called TestUnitHelper that includes static methods to eliminate some of the tedium involved with creating unit tests with FlexUnit. There is some overlap with some of the points Theo touches on in terms of parsing test methods, but Eric's API is straight forward and gets the job done. Eric is a busy man, be sure to check out the trove of other useful APIs while you are there.
Daniel Rinehart gives a decent explanation of how to handle asynchronous calls in FlexUnit tests in the Flex Cookbook (beta). He also writes up another similar example over on his blog. I'm still not quite there with this concept, but these articles are a step in the right direction.
1/23/08 - I found this page with a huge repository of FlexUnit resources.
Django Authentication from Flex
Django 'salts' passwords for added protection. They use SHA1 with a random key applied to further obfuscate the resulting hash. This is a good thing, but it threw me off for a bit. I don't want to send the unencrypted passwords over the wire, so I needed to grab the hash string from Django, break it apart, and reassemble it inside of flex. This did the trick:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | private function onGetUsersComplete( re:ResultEvent ):void { var users:Array = re.result as Array; var userArray:Array = []; for ( var ii:int = 0; ii < users.length; ii++ ) { var user:UserVO = users[ii] as UserVO; userArray.push( user ); trace( users[ii].first_name ); } var isValidUser:Boolean = false; loginService.removeEventListener(ResultEvent.RESULT, onGetUsersComplete); for ( var i:int = 0; i < users.length; i++ ) { if ( users[i].username == this.username ) { currentUser = users[i] as UserVO; var salt:String = users[i].password.split('$')[1]; //django specific password scheme password = 'sha1$' + salt + '$' + SHA1.hash( salt + password ); loginService.verify_credentials( username, password ); loginService.addEventListener(ResultEvent.RESULT, onVerifyCredentialsResult, false, 0, true ); isValidUser = true; } } if ( !isValidUser ) { sendNotification( ApplicationFacade.LOGIN_FAILED, "Invalid Username" ) } } |
PureMVC – An overview
Chandima Cumaranatunge has written a great introduction to PureMVC. I'm working on my 2nd 'non-trivial' PureMVC application write now, a photography studio managment/client ordering system. To be fair to Cairngorm, I only evaluated it when my Actionscript knowledge was.. well, less than it is now. At the time I couldn't grasp PureMVC. But in the meantime I have worked and studied a bit and when I came back to PureMVC, the startling simplicity of it, along with Cliff Hall's implementation of familiar design patterns allowed me to build applications that are structurally sound.
On a related note, I picked up Mr. Cumaranatunge's book, Actionscript Design Patterns, a couple of weeks ago. It's a great book.
Cryptic changes to crossdomain.xml?
This was a huge struggle for me. I am creating a Flex application that uses SlideShowPro Director as the source for photo gallery information. I am serving the Flex application from my home server since it is using a Django backend, and I haven't committed to a hosting solution as of yet. So that means that I need to access data across domains, and that of course means that I need a properly configured crossdomain.xml. Right?
So I search around for hours. crossdomainxml.org sure makes it look simple:
1 2 3 4 5 | <?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <allow-access-from domain="*" /> </cross-domain-policy> |
I mean, what could be easier? Look at the asterisk! That means everything! Right? Right...
I read the Crossdomain Article by Colin Moock. I trust him, he writes killer books. A shame the article was written years ago, I suppose. It is linked everywhere as a place to get the information. Even security articles on Adobe.com use the above format.
* shakes fist at sky *
It won't work.
So finally I look at my console in Flex Builder. It has a clear concise message letting me know that my syntax is wrong in the crossdomain.xml file and that it is being ignored as a result. Wtf?
I read a few more papers on the subject, but don't really see anything that would indicate where my file is wrong.
So I finally look at adobe.com's crossdomain.xml.
1 2 3 4 5 | <?xml version="1.0"?> <cross-domain-policy> <allow-access-from domain="*.macromedia.com" secure="false"></allow-access-from> <allow-access-from domain="*.adobe.com" secure="false"></allow-access-from> </cross-domain-policy> |
Well, that's precious. It is just as easy, heck, easier. A shame nobody bothered to mention it.


















