Extending ArrayCollection to Implement Inbuilt Filter Functionality

Now a days many of the data-centric Flex (Flash Builder) applications are using DataGrid/AdvancedDataGrid. DataGrid is a one of the powerful component in Flex.

I’ve executed couple of projects around these components, where I used to implement search functionality (filtering data based on certain criteria). In order to simplify filtering, I’ve created custom class around ArrayCollection (which we’re extensively using for dataProvider), which will help to reduce a bit of code for me…

Limitation of this code is, we can only add single column criteria for filtering data.
e.g. in one criteria would be dataField=”name” & filterValue=”Some Keyword”, second would be growth=”30″ likewise.. what we can’t add is something like multiple fields in single criteria, “dataField”=”name, growth” & filterValue=”Some Keyword”.. Also we can not do any conditional search, e.g. value>10..

Attached code will produce following result.
[SWF]http://chintanbuch.com/wp-content/uploads/2011/08/arraycollection_filter_1.swf, 250, 300[/SWF]

There are two classes, which we need to use in order to implement search capablity:

FilterCriteriaVO:

1
2
3
4
5
6
7
8
9
10
11
public class FilterCriteriaVO extends Object
{
	public var dataField    :String;
	public var filterValue  :*;
	public var exactMatch   :Boolean;
 
	public function FilterCriteriaVO()
	{
		super();
	}
}

ArrayCollectionEx:

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
public class ArrayCollectionEx extends ArrayCollection
	{
		/**
		 * This array will have "Data Field of Column", "Filter Value" & "Exact Match Flag" pair
		 * - "Data Field of Column" is on which we want to filter
		 * - "Filter Value" with what we want to filter
		 * - "Exact Match Flag" will check for the exactly matching value, instead of part of value
		 * */
		public var dataFilterCriteria	:Array = new Array();
		private var strFilterItemValue	:String;
		private var strFilterFor		:String;
 
		public var customFilterFunction:Function;
 
		public function ArrayCollectionEx(source:Array=null)
		{
			super(source);
			filterFunction = dataFilterFunction;
		}
 
		protected function dataFilterFunction(dataValue:Object):Boolean
		{
			if(dataFilterCriteria.length < 1) {return true;}
			if(customFilterFunction != null){return customFilterFunction(dataValue);}
 
			var filterMe:Boolean;
			var dataItem:Object = dataValue;
			if(dataFilterCriteria.length > 0) {
				for(var i:int=0; i<dataFilterCriteria.length; i++) {
					if((dataFilterCriteria[i] as FilterCriteriaVO).exactMatch) {
						if(dataItem[(dataFilterCriteria[i] as FilterCriteriaVO).dataField] == (dataFilterCriteria[i] as FilterCriteriaVO).filterValue)
							{filterMe = true;}
						else	
							{return false;}
					} else {
						strFilterItemValue = (dataItem[(dataFilterCriteria[i] as FilterCriteriaVO).dataField] as String).toLowerCase();
						strFilterFor = (dataFilterCriteria[i] as FilterCriteriaVO).filterValue.toLowerCase();
						if(strFilterItemValue.indexOf(strFilterFor) > -1)
							{filterMe = true;}
						else
							{return false;}
					}
				}
			}
			return filterMe;
		}
 
		public function addFilterCriteria(filterCriteriaVO:FilterCriteriaVO):void
		{
			if(dataFilterCriteria.length > 0) {
				var foundSimilarCriteria:int = checkForItemInCriteria(filterCriteriaVO.dataField)
				if(foundSimilarCriteria > -1) {
					(dataFilterCriteria[foundSimilarCriteria] as FilterCriteriaVO).filterValue = filterCriteriaVO.filterValue;
					this.refresh();
					return;
				}
				dataFilterCriteria.push(filterCriteriaVO);
				this.refresh();
			} else {
				dataFilterCriteria.push(filterCriteriaVO);
				this.refresh();
			}
		}
 
		public function removeFilterCriteria(filterCriteriaVO:FilterCriteriaVO):void
		{
			if(dataFilterCriteria.length > 1) {
				var foundSimilarCriteria:int = checkForItemInCriteria(filterCriteriaVO.dataField);
				if(foundSimilarCriteria >= 0) {
					dataFilterCriteria.splice(foundSimilarCriteria, 1);
					this.refresh();
				}
			} else if(dataFilterCriteria.length == 1) {
				dataFilterCriteria = [];
				this.refresh();
			}
		}
 
		protected function checkForItemInCriteria(dataField:String = null):int
		{
			var foundSimilarCriteriaAt:int = -1;
			for(var i:int=0; i<dataFilterCriteria.length; i++) {
				if((dataFilterCriteria[i] as FilterCriteriaVO).dataField == dataField) {
					foundSimilarCriteriaAt = i;
					break;
				}
			}
			return foundSimilarCriteriaAt;
		}

Source Files