Friday, February 20, 2009

Custom item renderers for Lists, ComboBoxes, and DataGrids

If you haven't already read these articles on creating custom item renderers then do so now, they will save you a lot of time. I wish I had found them a few days ago!

  • http://blogs.adobe.com/aharui/2007/03/thinking_about_item_renderers_1.html

  • http://blogs.adobe.com/aharui/2007/04/more_thinking_about_item_rende.html


  • Who thought that creating a CheckBox list would be so difficult? I've actually ended using a custom CheckBoxList class that just puts CheckBox components directly into a VBox instead of using a List with a CheckBox itemRenderer because I was having too many difficulties getting it to work.

    Most of my problems are cause by two things:
  • When filtering and scrolling the list I found that the checkboxes would lose their selected state. I know the renderers are recycled, but I still couldn't get it to work consistently.

  • I had difficulty changing the selected property of my data items through ActionScript code (e.g. select all, select none, etc). I couldn't get the renderers to update properly and have the right checked value.


  • Most likely it is just my lack of understanding...

    Friday, February 13, 2009

    Flex AutoComplete/Chooser component

    I have been trying to use the AutoComplete component from Adode for a few weeks now, and it has been rather painful. I keep finding problems with it, and it has been frustrating my users a lot. There is a modified version by Jens Krause that is much better.

    But I still wasn't satisfied, so I started looking around for another auto-complete component, and came across this Chooser made by Hillel Coren. Check it out, it's very powerful and best of all it's freely available.

    Thursday, February 5, 2009

    Calling functions on applications loaded using SWFLoader

    Following on from my last post on passing parameters to an application that is loaded using SWFLoader, this post will show you how to call a function on an application.
    Here is the code to load swf:
    var loader:SWFLoader = new SWFLoader();
    loader.addEventListener(Event.INIT, swfLoaded);
    loader.load("AnotherSWF.swf");
    And here is the code to handle adding the new swf content application:
    private function swfLoaded(event:Event):void {
      var content:DisplayObject = loader.content;
      // Or if you don't have the loader:
      // content = event.target.content;
      // add loaded SWF to a UIComponent to show it on the screen
      uicomponent.addChild(content);
      var sysmgr:SystemManager = (content as SystemManager);
      // must wait for the swf application to finish loading
      // otherwise the application is null
      sysmgr.addEventListener(FlexEvent.APPLICATION_COMPLETE, swfAppComplete)
    }
    And here is the code to call a function on the swf application:
    private function swfAppComplete(event:FlexEvent):void {
      var sysmgr:SystemManager = (event.currentTarget as SystemManager);
      var swfApp:Application = (sysmgr.application as Application);
      // call your function here, maybe add error checking
      if (swfApp.hasOwnProperty("helloWorld")) {
        var helloWorld:Function = (swfApp["helloWorld"as Function);
        helloWorld("hi");
      }
    }
    Note that the SWFLoader has 2 events that could be used:
  • Event.COMPLETE ("complete") - dispatched when the content loading is done
  • Event.INIT ("init") - dispatched when the properties and functions of the loaded SWF are accessible


  • If you want more reading on this subject, here is another good blog on Nested SWF communication.

    Wednesday, February 4, 2009

    Passing parameters to a loaded SWF application

    Today I was trying to figure out how to load an SWF that contained another Flex Application and embed it into my main application. This is the code that does it:
    var loader:SWFLoader = new SWFLoader();
    loader.addEventListener(Event.COMPLETE, function(event:Event):void {
        var content:DisplayObject = loader.content;
        uicomponent.addChild(content);
    });
    loader.load("SWFLoaderApp.swf");

    Then once I figured that out, I wanted to know how to pass parameters into the loaded SWF, and here is how that can be done. Change the load line to:
    loader.load("SWFLoaderApp.swf?test=hi");

    Then in your SWF application code, you should be able to get those parameters like this:
    if (application.loaderInfo != null) {
        var url:String = application.loaderInfo.url;
        var qm:int = url.lastIndexOf("?");
        if (qm != -1) {
            var query:String = url.substr(qm + 1);
            var params:Array = query.split("&");
            for (var i:int = 0; i < params.length; i++) {
                var param:String = params[i];
                var nameValue:Array = param.split("=");
                if (nameValue.length == 2) {
                    var key:String = nameValue[0];
                    var val:String = nameValue[1];
                    trace(key + "=" + val);
                }
            }
        }
    }

    ** Update:
    After some more testing I noticed that the above code doesn't always reliably work. And here is what I think is happening. When you start up your main application, the Application.application property is set. Then when you load an SWF using the above code, it shares this same application. So, the better way to get at the parameters passed in through the SWFLoader url is to simply get the parameters property right from your second (loaded) application like this:
    // inside your loaded swf application
    var params:Object = parameters;
    trace("test=" + params["test"]);

    From reading the documentation on the mx.core.Application page:
    There are two sources of parameters: the query string of the Application's URL, and the value of the FlashVars HTML parameter (this affects only the main Application).

    I found this blog quite helpful too in solving this problem:
    http://rahulmainkar.blogspot.com/2007/11/swfloader-and-nested-application.html.