logo

Flex: Highlight Matching Strings In DataGrid Columns

It seems a logical continuation of the view filtering Flex demo to highlight each column and show the user where the matches were found.

In the shot below I've filtered the grid to only show items with "ar" in the description column and then underlined the matching part of the text and marked it green (click the image to go to the demo):

ScreenShot005

What surprised me was that I couldn't find a documented solution for this after a few Googles and I ended up deciding to tackle it myself.

Before long (an hour or two), I had what you see above, which just goes to show the power of Flex. I'd still class myself as somewhere slightly above "intermediate" level, yet I can already extend the functionality of the DataGrid simply by applying the bits of knowledge I've picked up along the way.

How Did I Do That?

Well, the (Advanced)DataGrid itself doesn't give us any way of doing this out of the box, so I had to use a custom ItemRenderer for the description column. Now, don't worry, this isn't as scary as it might sound. Creating your own components is really easy.

To tell the grid to use a custom component is this easy:

<mx:AdvancedDataGrid 
        dataProvider="{documents}"
        id="viewExpenses">
    <mx:columns>
        <mx:AdvancedDataGridColumn headerText="Date" 
                dataField="date"/>
        <mx:AdvancedDataGridColumn headerText="Description"
                dataField="description"
                itemRenderer="components.CustomColumnRenderer" />
    </mx:columns>
</mx:AdvancedDataGrid>

Notice I've set the itemRenderer property for the second column to "components.CustomColumnRenderer". 

All that "components.CustomColumnRenderer" tells Flex to do is look inside a folder called "components" for a file called "CustomColumnRenderer.mxml". It's this MXML file which contains the code for what appears in the column.

Creating a New Component

To add your own component, first turn to your Flex app's file structure, as below, where I've already added the folder and the component:

ScreenShot002

As you can see, the main application file is called Accounts.mxml and lives inside the app's "src" folder. Notice the "components" subfolder I've created inside the "src" folder. To create it was as easy as right-clicking the src folder and choosing "Create Folder".

With this new folder I then right clicked it and choose New -> MXML Component. As below:

 ScreenShot003

In the next dialog I entered the name of the component and which Flex component to base it on. As below:

 ScreenShot006

This gives us a new component which is based on a Label object and inherits all it's properties and methods. We can go on to extend it to do whatever it is we like. In our case we want to highlight some text in it. You can see the whole of the code for the component in this file, but the important part is the function below (where I've left bits missing so it's more readable):

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
        //Still run the function we're over-riding
        super.updateDisplayList(unscaledWidth, unscaledHeight);
        
        //What we're looking for
        var token:String = this.parentApplication.input.text;

        //Where it is
        var begin:int = this.text.toLowerCase().indexOf(token.toLowerCase());
                                
        if ( begin > -1 ){
                //Highlight it
                var tr:TextRange = new TextRange(this, true, begin, begin+token.length);
                tr.color = "green"; 
                tr.fontWeight = "bold";
                tr.textDecoration = "underline";
        }
}

The key to this solution is that we're over-riding the "updateDisplayList" method of the label. All of the Flex UI Components implement this method and you can over-ride it so you have the ultimate control over it's appearance each and every time its "refreshed". Or at least that's my understanding of how it work. Over-riding this method seems to be common practice among Flex developers.

It should be fairly obvious what the function is doing. Notice the parentApplication property is used to get access to the main application that this component is a part of and read the value of the "filter" field on it. It then creates a TextRange on the Label component's text and highlights it.

So, fairly easy, no? 

Memory Hungry?

If you're like me you probably worry about creating your own component for use in a cell in every row of a "view"? The more rows the more likely your "poor programming practices" will be reflected in poor performance. Well, worry not. Apparently Flex only creates enough instances of the cell's itemRenderers to cover the visible rows on the screen. If the datagrid had a million rows the fact each cell has its own renderer shouldn't affect performance. Apparently. Seems true as far as I can tell. On my live Accounts db with about a thousand rows the performance is just as with 10 or so.

Further Reading

If you want to know more about custom item renderers then this quick start guide is well worth the read and gives other examples of how much you can customise the data grid.

Comments

  1. Hi Jake,

    Very good ! (and very useful !)

    Every day I want more Flex

    Thanks ! ;)

  2. Nothing better than a new feature that does not impact performance. Thanks!

  3. THAT IS PIMP!!!

    I think that is awesome. Useful, clean, and professional; everything you need for a successful add-in feature.

    Thanks brother.

    • avatar
    • MJWalky
    • Mon 23 Nov 2009 09:15 AM

    Can this be applied to a Hierarchical Data in an AdvancedDataGrid.

      • avatar
      • Jake Howlett
      • Mon 23 Nov 2009 02:53 PM

      I remember trying but can't remember the outcome. Can't see why not though.

      Hide the rest of this thread

        • avatar
        • MJWalky
        • Tue 24 Nov 2009 05:40 AM

        I am trying to apply the same CustomColumnRenderer as a groupItemRenderer to the column having the Hierarchical data. However, doing that the hierarchical data is getting displayed as a linear data. That means now the expand icons are not getting displayed. Though the funtionality of highlighting the matching string still works. The only problem that I have is not able to see the expand(disclosure) icons. Can anyone help me out on this.

    • avatar
    • Ravish
    • Fri 11 Jun 2010 06:23 AM

    Hi,

    I just happened to go through the demo. and I entered ".net" without quotes.

    It throws an error.

    Any comments regarding this would be really helpful.

    Thanks.

    • avatar
    • Ravish
    • Fri 11 Jun 2010 06:42 AM

    Hi,

    I just found the solution.

    if you change the code to

    tr = new TextRange(this);

    tr.text = this.text;

    tr.beginIndex = begin;

    tr.endIndex = begin + token.length;

    then it works..

    i got it from. http://nwebb.co.uk/blog/?p=20&cpage=1#comment-124616

  4. Excellent Post, very Useful

  5. awesome article. so useful. :)

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:


About This Page

Written by Jake Howlett on Thu 3 Sep 2009

Share This Page

# ( ) '

Comments

The most recent comments added:

Skip to the comments or add your own.

You can subscribe to an individual RSS feed of comments on this entry.

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

More Content