Learning Flex 4 | O'Reilly Media

Google Search Application in Flex 4

with one comment

Unfortunately, the Yahoo! web services, which we consumed using the ASTRA Flex library and introduced near pages 232-233, are deprecated and discontinued, devaluing the book I realize many of you bought with hard-earned money. In light of this reversal, I applied myself to replacing the YahooSearch example with something comparable.

This alternative arrangement consumes the Google Search API, which is simplified into callable methods exposed through googleas3api.swc—an ActionScript library package created by Joris Timmerman (my apologies if I am incorrect about the creator and maintainer). Because googleas3api is an ActionScript library and not a Flex library, we can’t instantiate  the service component in MXML like we did with the Yahoo! search component (but to be honest, I didn’t even try so maybe I am wrong about that), so this alternate example uses more ActionScript and looks a little different. On the bright side, I believe that is good for you; on the other hand, it will require more of your intuition at timesto understand the similarities and differences between the original YahooSearch code illustrated in the book, which will fail at runtime (i.e. when you perform a search), and this GoogleSearch variation, which looksdifferent in code, but performs as you would expect.

Application: GoogleSearch.mxml

The application requires two supporting libraries—as3corelib.swc and googleas3api.swc. Make sure to download these, unzip if necessary, and copy their SWC files into the “libs” folder of your Flex 4 project.

<?xml version="1.0" encoding="utf-8"?>
<s:Application
 xmlns:fx="http://ns.adobe.com/mxml/2009"
 xmlns:s="library://ns.adobe.com/flex/spark"
 xmlns:mx="library://ns.adobe.com/flex/mx"
 creationComplete="onComplete();"
 defaultButton="{searchButton}">
 
 <fx:Script>
  <![CDATA[
   /**
    * This project requires two reference libraries.
    * 
    * as3corelib.swc:
    *   https://github.com/mikechambers/as3corelib
    *   (Downloads > Download Packages > as3corelib-93.zip)
    *   Find the .swc file in the extracted "lib" folder.
    *
    * googleas3api.swc:
    *   http://code.google.com/p/googleas3api
    *   (Downloads > googleas3api.swc)
    *
    * Copy/paste or drag/drop these into the "libs" folder
    * for this Flex 4 project.
    */
   import be.boulevart.google.ajaxapi.search.GoogleSearchResult;
   import be.boulevart.google.ajaxapi.search.web.GoogleWebSearch;
   import be.boulevart.google.events.GoogleAPIErrorEvent;
   import be.boulevart.google.events.GoogleApiEvent;
   
   import mx.collections.ArrayCollection;
   
   
   private var googleSearch:GoogleWebSearch;
   
   private var searchResultAC:ArrayCollection;
   
   
   
   private function onComplete():void
   {
    googleSearch = new GoogleWebSearch();
    googleSearch.addEventListener(
       GoogleApiEvent.WEB_SEARCH_RESULT, searchResult);
    googleSearch.addEventListener(
       GoogleAPIErrorEvent.API_ERROR, searchFault);
   }
   
   private function onSearch():void
   {
    // See the API library example here..
    // http://code.google.com/p/googleas3api
    // "en" means English
    // ..try "de", which is Danish, etc..
    googleSearch.search(queryTI.text, 0, "en");
    
    // you can also leave the string out, which may
    // allow Google to introspect by IP and "guess"
    // the correct language (I am supposing this):
    //  googleSearch.search(queryTI.text, 0);
   }
   
   private function searchResult(event:GoogleApiEvent):void
   {
    // Cast the event.data response as GoogleSearchResult
    // to enable code completion and compile-time error checking.
    var searchResult:GoogleSearchResult;
    searchResult = event.data as GoogleSearchResult;
    
    // searchResult.results is an Array, so we can pass it
    // into a new ArrayCollection and use it as a dataprovider.
    searchResultAC = new ArrayCollection(searchResult.results);
    resultsList.dataProvider = searchResultAC;
   }
   
   private function searchFault(event:GoogleAPIErrorEvent):void
   {
    // Catch search faults and trace to the console.
    trace(String(event.responseDetails));
   }
  ]]>
 </fx:Script>
 
 <s:VGroup left="10" right="10" top="10" bottom="10">
  <s:Label text="Google Search:" fontWeight="bold"/>
  <s:HGroup>
   <mx:FormItem label="Query:" fontWeight="bold">
    <s:TextInput id="queryTI" width="350"/>
   </mx:FormItem>
   <mx:FormItem>
    <s:Button id="searchButton" label="Search"
        click="onSearch();"/>
   </mx:FormItem>
  </s:HGroup>
  <s:List id="resultsList" width="100%" height="100%"
     itemRenderer="SearchItemRenderer"/>
 </s:VGroup>
 
</s:Application>

SearchItemRenderer.mxml

The ItemRenderer used in the application is created using the same approach described in pages 235-238. However, note the use of the Ternary Operator to create a shorthand if..then conditional statement; this is described on page 354 as an inline if..then for use in MXML code, but here I’m demonstrating its use in an ActionScript-only context.

Note: To work with the application code, above, this custom ItemRenderer needs to be created in the default package (i.e. the local package), the same folder as GoogleSearch.mxml.

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    autoDrawBackground="true"
    creationComplete="onComplete();">
 <fx:Script>
  <![CDATA[
   import be.boulevart.google.ajaxapi.search.web.data.GoogleWebItem;
   import flashx.textLayout.conversion.TextConverter;
   
   private function onComplete():void
   {
    // Cast the data record as GoogleWebItem to expose
    // code commpletion and enjoy tighter compile-time
    // error-checking. We could use object notation
    // on the data variable like this..
    //   urlLabel.text = "From: " + data.url;
    // but casting the object is preferred.
    var item:GoogleWebItem = data as GoogleWebItem;
    
    urlLabel.text = "From: " + item.url;
    
    // Create "content teaser" with no more than 100 chars..
    var teaserString:String=item.title + " | " + item.content;
    
    // Shorthand if..then using the ternary operator..
    // See pg. 354 for background on this syntax.
    teaserString = (teaserString.length>99)
        ? teaserString.substr(0,99)+"..[more].."
        : teaserString ;
    
    contentTA.textFlow = TextConverter.importToFlow(teaserString,
          TextConverter.TEXT_FIELD_HTML_FORMAT);
    
    callLater(invalidateDisplayList);
    callLater(validateNow);
         
   }
   
   private function onClick(event:MouseEvent, url:String):void
   {
    var urlRequest:URLRequest = new URLRequest(url);
    navigateToURL(urlRequest, "_blank");
   }
  ]]>
 </fx:Script>
 <s:VGroup width="100%" gap="2" paddingTop="2" paddingBottom="2">
  
  <s:Label id="urlLabel" fontWeight="bold" buttonMode="true"
     click="onClick(event, data.url);"/>
  
  <s:TextArea id="contentTA" width="100%" heightInLines="1"
     verticalScrollPolicy="off"
     editable="false" selectable="false"
     contentBackgroundAlpha="0"
     borderVisible="false"/>
 </s:VGroup>
</s:ItemRenderer>

Advertisements

Written by elrobis

29 September 2011 at 10:06 am

Posted in AIR, Flex 4

One Response

Subscribe to comments with RSS.

  1. Very cool. Much cleaner than the one one I came up with. Thanks!

    Torrey Nommesen (@torrey)

    14 October 2011 at 12:51 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: