views:

105

answers:

2

Hi I am working on a search tool for my website in Flex. I want it to work exactly like the "Spotlight" tool on MAC desktop. "http://www.recipester.org/images/6/66/How_to_Use_Spotlight_to_Search_on_Mac_OS_X_42.png" The link is to an image of spotlight.

I want to create almost the same thing in FLEX. What I currently have is a "Autocomplete" box, and I get all the data I want in it. Code for the autocomplete is below:

<auto:AutoComplete borderStyle="none" id="txt_friends_search" 
        textAlign="left" prompt="Search Friends" dataProvider="{all_friends_list}" 
        allowEditingNewValues="true" allowMultipleSelection="true" allowNewValues="true" 
        backspaceAction="remove" labelField="label"
        autoSelectEnabled="false" matchType="anyPart" 
        height="23" right="400"  top="1" dropDownItemRenderer="{new ClassFactory(weather.index_cloud_global_search_item_renderer)}" />

And my ItemRenderer looks like :

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    width="100%" height="100%" 
    verticalGap="0" horizontalGap="0"
    creationComplete="init()"
    verticalScrollPolicy="off" horizontalScrollPolicy="off" 
    verticalAlign="middle">
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            import mx.collections.ArrayCollection;
            import com.hillelcoren.utils.StringUtils;
            import mx.utils.StringUtil;
            import mx.events.FlexEvent;
            import mx.controls.List;

        public function init():void
        {

        }                                                           
    ]]>
</mx:Script>

<mx:HBox width="100%" verticalGap="0" horizontalGap="0">
    <mx:HBox borderThickness="1" width="75" borderStyle="solid" horizontalAlign="left" horizontalScrollPolicy="off">
        <mx:Label id="type"  text="{data.type}" fontSize="12"/> 
    </mx:HBox>
    <mx:HBox borderThickness="1" width="75" borderStyle="solid" horizontalAlign="left" horizontalScrollPolicy="off">
        <!--mx:Label id="nameLabel"  text="{data.label}" fontSize="12"/-->
        <mx:List id="names" dataProvider="{all}"    
    </mx:HBox>      
</mx:HBox>      

<!--mx:Box id="colorBox" borderStyle="solid" width="50" height="25"/-->
<mx:Spacer width="15"/>

This shows the type and label of everything, example:

  • Friends ABC
  • Friends XYZ
  • Messages This is the message
  • Messages example for messages
  • Files filename1
  • Files filename123

I believe you get my point there.

But what I want to create is something like:

Friends ABC XYZ Messages This is the message example for messages Files filename1 filename123 MoreFiles

Can someone plz help me in this. I actually have no idea how to move forward in this.

Let me know if you want more clarification on anything.

Regards Zeeshan

+2  A: 

You may want to try something like this. This is just a sample I whipped up, but the basics are there for you to apply to your solution. What this is doing is creating a custom item render (as you've already done), but the container that it's rendering, it adjusts the data set slightly within set dataProvider so that it sorts and filters.

Screenshot

Obviously, you can expand upon this even further to add common icons, formatted text ... etc. The renderer has an explicit width set for the first "column" text. This is to better align results, but should probably be done while the list is being built (based on the string lengths of the values in the result set). Cheers ;)


Application.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*">
 <mx:Script>
  <![CDATA[
   [Bindable]
   private var items:Array = [
    { type:'friends', value:'abc' },
    { type:'friends', value:'xyz' },
    { type:'messages', value:'this is the message' },
    { type:'messages', value:'example for messages' },
    { type:'files', value:'filename1' },
    { type:'files', value:'filename123' },
   ];
  ]]>
 </mx:Script>
 <local:SpotlightComboBox 
  dataProvider="{items}"   
  width="400" />
</mx:Application>

SpotlightComboBox.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox 
 xmlns:mx="http://www.adobe.com/2006/mxml"
 itemRenderer="SpotlightComboBoxItemRenderer">

 <mx:Script>
  <![CDATA[   
   override public function set dataProvider(value:Object):void 
   {
    super.dataProvider = sort_and_filter(value as Array);
   } 

   private function sort_and_filter(source:Array):Array
   {
    if (source && source.length > 1) {     
     source.sortOn('type', Array.CASEINSENSITIVE);
     var last:String = "";
     for each(var entry:Object in source) {      
      var current:String = entry.type;
      if (current != last)            
       last = current      
      else
       entry.type = "";
      last = entry.type;
     }
    }

    return source;
   }     
  ]]>
 </mx:Script>

</mx:ComboBox>

SpotlightComboBoxItemRenderer.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"&gt;
 <mx:Script>
  <![CDATA[

  ]]>
 </mx:Script>

 <mx:HBox width="100%">
  <mx:Label width="100" text="{data.type}" />
  <mx:Label text="{data.value}" />
 </mx:HBox>
</mx:Canvas>
Maximus
Will this be able to give me the autocomplete functionality? That is very important for me, I need an autocomplete functionality.
Zeeshan Rang
This is just a subclass of ComboBox, but in theory you could subclass an autocomplete component. The example I provided was proof-of-concept, not a finished solution. Just modify the code to extend an AutoCompleteBox (or whatever it's called) and go from there ;)
Maximus
+1  A: 

Since you're offering a bounty, I'll submit a different answer (as the previous one is technically valid).

Step #1: Download the Adobe Autocomplete Component integrate the class into your project.

Step #2: Create a new component that is derived from AutoComplete (I called mine SpotlightField.mxml)

<?xml version="1.0" encoding="utf-8"?>
<AutoComplete 
    xmlns="com.adobe.flex.extras.controls.*" 
    xmlns:mx="http://www.adobe.com/2006/mxml"
    creationComplete="init()"
    labelField="value"  
    itemRenderer="SpotlightFieldRenderer">

    <mx:Script>
        <![CDATA[

            private function init() : void
            {
                this.filterFunction = substringFilterFunction;
            }                                                       

            private function substringFilterFunction(element:*, text:String):Boolean
            {
                var label:String = this.itemToLabel(element);
                return(label.toLowerCase().indexOf(text.toLowerCase())!=-1);
            }
        ]]>
    </mx:Script>        
</AutoComplete>

Step #3: Create the ItemRenderer you want to apply to this new component (I called mine SpotlightFieldRenderer.mxml). Note that the code is the same as the previous example, but I'll post it again for completeness.

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"&gt;
    <mx:Script>
        <![CDATA[

        ]]>
    </mx:Script>

    <mx:HBox width="100%">
        <mx:Label width="100" text="{data.type}" />
        <mx:Label text="{data.value}" />
    </mx:HBox>
</mx:Canvas>

Step #4: Update the AutoComplete.as class as follows:

/**
 *  @private
 *  Updates the dataProvider used for showing suggestions
 */
private function updateDataProvider():void
{
    dataProvider = tempCollection;
    collection.filterFunction = templateFilterFunction;
    collection.refresh();

    sort_and_filter(collection);

    //In case there are no suggestions, check there is something in the localHistory
      if(collection.length==0 && keepLocalHistory)
      {
        var so:SharedObject = SharedObject.getLocal("AutoCompleteData");
        usingLocalHistory = true;
        dataProvider = so.data.suggestions;
        usingLocalHistory = false;
        collection.filterFunction = templateFilterFunction;
        collection.refresh();
      }
  }

private function sort_and_filter(source:Object):Object
{
    if (source && source.length > 1) {   
        trace (source.length);  
        source.sortOn('type', Array.CASEINSENSITIVE);           
        var last:String = "";
        for each(var entry:Object in source) {      
            var current:String = entry.type;
            if (current != last)            
                last = current      
            else
                entry.type = "";
            last = entry.type;
        }
    }

    return source;
}  

You'll notice that the *sort_and_filter* function is defined, and called on the collection within updateDataProvider. The app now looks like this:

Screenshot

That's it. The sample application now looks like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*">
    <mx:Script>
        <![CDATA[
            [Bindable]
            private var items:Array = [
                { type:'friends', value:'abc' },
                { type:'friends', value:'xyz' },
                { type:'messages', value:'this is the message' },
                { type:'messages', value:'example for messages' },
                { type:'files', value:'filename1' },
                { type:'files', value:'filename123' },
            ];
        ]]>
    </mx:Script>        
    <local:SpotlightField dataProvider="{items}" width="400" />
</mx:Application>

Let me know if you have any further questions. There is still a bit of work to do depending on how you want to display the results, but this should get you 95% of the way there ;)

Maximus
What you did here, is exactly what my code is doing too. I think you did not understood what I want to do. I want to create something like the spotlight search in mac. It should group things into categories.
Zeeshan Rang
Zeeshan, I updated the solution to show you where to plug the sort code into the AutoComplete class. This will do (what I assume is) exactly what you were looking for. The only problem I can foresee is if we have conflicting definitions of what "Grouping" means (as far as results).
Maximus
Thanks alot Maximus, this is exactly what I want to do. I am sorry for being a naive. But I was trying to do what you have told here, but I got errors in a autocomplete.as file. I will look into this again tomorrow. I hope it will work. Thanks again.
Zeeshan Rang
The above examples need a bit of "tweeking" in order to get them to work. If you still have trouble, I can bundle a project for you and link it so you can test it. I figure you'd want to get it working yourself first though (as that's more fun than just cutting and pasting :P)
Maximus
haha... thanks maximus. I would really appreciate if you could send a project as you mentioned. I am still getting errors in what I am trying to do.
Zeeshan Rang
Here ya go.http://www.zshare.net/download/717985109c90f0da/
Maximus
Thanks alot Maximus
Zeeshan Rang
Maximus- I am sorry again, but I am still getting "Unable to load SWC libs" error in your project. I did added the autocomplete-1.0.swc, but still I get the same error. What should I do?
Zeeshan Rang