views:

29

answers:

1

I have flex 4 and writing my own autocomplete component (based on the popupanchor) to search for different books. In the dropdown box, how can I highlight the text that matches? For instance, a user types in "ema" and the search returns "Pet Sematary"....I want to highlight the letters "ema" within "Pet Sematary"

A: 

Wrote auto-complete a week ago :) You need to use Spark text components and pass custom TextFlow to them:

private function init():void
{
    var textFlow:TextFlow = new TextFlow();
    var paragraph:ParagraphElement = new ParagraphElement();
    textFlow.addChild(paragraph);
    var elements:Vector.<FlowElement> = highlight("Pet Sematary", "Se");
    var n:int = elements.length;
    for (var i:int = 0; i < n; i++)
    {
        paragraph.addChild(elements[i]);
    }
    label.textFlow = textFlow;
}

private function highlight(text:String, query:String):Vector.<FlowElement>
{
    var result:Vector.<FlowElement> = new Vector.<FlowElement>();
    // since we need to compare ignore-case we can not use split()
    // and have to collect indexes of "query" matches in "text"
    var indexes:Vector.<int> = new Vector.<int>();
    var index:int = 0;
    var textLowerCase:String = text.toLocaleLowerCase();
    var queryLowerCase:String = query.toLocaleLowerCase();
    var queryLength:int = query.length;
    while (true)
    {
        index = textLowerCase.indexOf(queryLowerCase, index);
        if (index == -1)
            break;

        indexes.push(index);
        index += queryLength;
    }

    // now add SpanElement for each part of text. E.g. if we have 
    // text="aBc" and query is "b" then we add "a" and "c" as simple
    // span and "B" as highlighted span.
    var backgroundColor:uint = 0xFFCC00;
    var n:int = indexes.length;
    if (n == 0) // no matches
    {
        addSpan(result, text);
    }
    else
    {
        var startIndex:int = 0;
        for (var i:int = 0; i < n; i++)
        {
            if (startIndex != indexes[i])
                addSpan(result, text.substring(startIndex, indexes[i]));

            addSpan(result, text.substr(indexes[i], queryLength),
                        backgroundColor);

            startIndex = indexes[i] + queryLength;
        }

        if (startIndex != text.length)
            addSpan(result, text.substr(startIndex));
    }

    return result;
}

private function addSpan(vector:Vector.<FlowElement>, text:String, 
    backgroundColor:* = "transparent"):void
{
    var span:SpanElement = new SpanElement();
    span.text = text;
    span.backgroundColor = backgroundColor;
    vector.push(span);
}

MXML code:

<s:RichEditableText editable="false" multiline="false" 
    selectable="false" id="label"
    horizontalCenter="0" verticalCenter="0"/>

P.S: If you will have troubles with popup taking focus - add it manually to the toolTipChildren:

systemManager.toolTipChildren.addChildAt(child, 0);
Maxim Kachurovskiy