The above Screen Shots look promising , don't they ?
So, How would one go about building such a control ? Well, I have it laid out in front of you .
1) Find all unique Strings in the same column
2) Build a lookup table that stores the Unique string and the row Indices for the rows that contain the Unique String
3) Once user builds a Filter Expression and clicks on "Ok" , Filter the Rows in the Table based on the Expression.
4) For Now , the Filter Expression can only be a sequence of strings that the user wants to see in the grid.
Ex : If your grid looks like this :
The filter expression would be a comma-separated string that contains the unique strings to match in the rows.
var _currentRowFilter = "Ajax,Moo"
The lookup Table would look like this :
_lookupTable Select All "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23" Ajax "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16" Moo "17,18,19,20,21,22,23"
so , if we want to filter the rows , we would need to :
1) Hide all Rows to begin with .
HideRows : this.lookupTable["Select All"]
2) Show only those rows that are found in the lookup table against the filter Terms.
That's about the algorithm / design for the extender to work .
Getting this working is another matter altogether.
Once you have understood this , lets start:
Find all unique Strings in the same column :
once you find all the unique strings in all subsequent rows for the same column , we will need to build the checkbox list that
will allows the user to select the filter Terms. I.e this :
This is a bit tricky , the way one would go about doing this would be :
Find out which Column the Extender is added in .Find the Cell Index of the Column , lets say _cellIndex
For all subsequent rows in the table, Lookup the innerText of the Cell with CellIndex cellIndex.
For Each Row
Read the innerText of the Cell at CellIndex cellIndex.
IF the string read is not yet present in the lookup Table then
add it to the lookup Table along with the rowIndex of the current Row
ELSE if string is already present in the lookupTable then
add the RowIndex to the lookupTable[string] location.
Once you have found all the Unique Strings , build the CheckBoxList and attach the appropriate handlers .
Once user builds a Filter Expression and clicks on "Ok" , Filter the Rows in the Table based on the Expression.
Hide All Rows .
Get all the Rows in the Table other than the header and the footer , _rowsInTable.
Get the Current Search Filter by adding all the strings that are checked in the CheckBoxList.
For each term in the Search Filter , get the appropriate row Indices ,
For each row Index in the Row Indices, _rowIndex
assign the cssClass _inFilterCssClass to the _rowsInTable[_rowIndex].
This is all neat , what if I have multiple columns in my GridView and I want to filter
each succeeding Column depending on the previous Column?
Well, I have thought about that too ..
This is what we would do :
Every FilterExtender (a) can have a Dependent Filter (b) , if filter (b) is used to filter data ( it raises the itemFiltered Event ),
then the Filter (a) has to rebuild its index to remove any index text
that was removed as a result of the filter expression on filter (b).
Important Note about the DependentFilterID
If a FilterExtender (a) has a FilterExtender (b) as its Dependent Filter ID , they both should have the matching values for the
InFilterCssClass and the NotInFilterCssClass attributes.
|TargetControlID||ID of the control upon clicking on which , the Filter is shown|
|OkButtonId||ID of the control upon clicking on which , the FilterExpression is applied and the filter is hidden|
|CancelButtonId||ID of the control upon clicking on which , the FilterExpression is NOT applied and the filter is hidden|
|EnableSelectAll||If the filter contains an option to "Select All" Rows|
|InFilterCssClass||The CssClass applied to all rows which are available from the Filter Expression.|
|NotInFilterCssClass||The CssClass applied to all rows which are NOT available from the Filter Expression.|
|FilterPanelID||The Panel Control which contains the Filter|
|itemSelected||When any filter Expression is Selected|
|itemFiltered||When the filter Expression is applied.|
|onOk||when the Control Referenced by OkButtonId is clicked|
|onCancel||when the Control Referenced by CancelButtonId is clicked|
Subscribing to the Events :
a) Markup :
<Raj:OptionPickerBehavior runat="server" ID="optionListPnl" TargetControlID="btnToggle" blah blah blah OnOkScript="okClickHandler" OnCancelScript ="cancelClickHandler" OnClientItemFiltered ="itemFilteredHandler" OnClientItemSelected ="itemSelectedHandler"> </Raj:OptionPickerBehavior>
$find("BehaviorId").add_onOk( okClickHandler ); $find("BehaviorId").add_onCancel( cancelClickHandler ); $find("BehaviorId").add_itemFiltered( itemFilteredHandler ); $find("BehaviorId").add_itemSelected( itemSelectedHandler );
That's it for now ! Do give feedback on the control if you get a chance to use it / look at it .