Archive for December, 2006

Grey Line

We’ve been invited to teach a one day hands-on Flex workshop during the upcoming AjaxWorld 2007 conference on March 19, 2007 in New York City. Here’s the detailed full day schedule of this workshop.

If you are planning to strat a new Flex project, this workshop will  be of a real value  to your developers. If you’d like to re-run this workshop at your company site, we can do it either as a one or two-day training.  Other introductory or advanced custom Flex training is also available.

See you in class.

Yakov Fain
Adobe Flex Certified Instructor

 

Š

Comments

 

Grey Line

It started as a simple task – I needed to store user preferences.  No problem SharedObject.getLocal() will do the job. Oh, by the way, we do not want to store the preferences on the local disk because users want to be able to switch workstations. SharedObject.getRemote()? No good. Who’s going to let you store the data on the server’s machine? And even if they will, how are you going to organize multi-user complex preferences?

Using DBMS is a no-brainer.  I’ll create a two-column table – userID and something with properties. What something? An object as a blob. What type of object? Hmm. How about ByteArray?  Rolling up the sleeves.

Before we proceed, let me remind you I spend many years doing  pure object-oriented programming in Java. You’ll see why it’s important in a little bit.

There is a lots of various user preferences to remember. For example, which is a default tab in TabNavigator, which columns should be visible in a datagrid and more.  Here’s what goues through my mind, “For simple preferences I’ll just use Strings and Numbers, and more complex ones I’ll put in a collection with key-value pairs. Then, I’ll create the object UserPrefs, add all the preferences to it, convert it into a ByteArray and will store it either in the SharedObject.data or send it over to a POJO for storage in the DBMS”.  Sounds good? Boy, I was wrong…

It started with the fact that I decided to use ActionScript 3 Dictionary class.  When I opened the language reference, I was surprised by several things:

a) The class Dictionary is inherited right from the Object and has only a couple of extra methods there. To iterate the dictionary, I was looking for a property length or something to know how many elements are there in my collection. Nope, there is not such thing there. Now it’s getting clearer how Flash Player’s VM is so light comparing to JVM.  No big deal. Will loop through the collection while it has some elements.

b) The fun began when I started adding my collections to the UserPrefs object trying  serialize them into the ByteArray for storing in the SharedObject.  When the user will start my application, I’ll de-serialize it using ByteArray.readObject(). Oopsie…Class deserialization is not supported in ActionScript 3. Need to recreate collections manually. But what if I’ll have collections inside collections?

Anyway, finally I got it to work…while debugging in Flash Player. The regular run-time kept giving me some errors…

My colleague  Anatole suggested, “Forget about Dictionary. In this case you can live with a simple Object, but use dynamic typing, and Flash will do deep copying”.  I followed his advice, the program became simpler, I got rid of my UserPref class and it works like a charm.  The following sample creates some hardcoded preferences for illustration purposes, converts them to byte array, saves them, and the on a button click retrieves and deserializes them. Conversion to byte array and back is done just to simplify communication with the Java back end, if any. Here’s the code:

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute”>
 <mx:Button x=”173″ y=”16″ label=”Save Hardcoded Preferences” width=”185″ click=”saveData()”/>
 <mx:Button x=”203″ y=”46″ label=”Read Preferences”  click=”getSavedData()”/>
 <mx:TextArea x=”86″ y=”76″ width=”356″ id=”txtOutput” height=”156″/>
 <mx:Script>
  <![CDATA[
        private var prefs:SharedObject;
        private const COOKIE_SIZE:int=10000;
        private function getSavedData():void{

          prefs = SharedObject.getLocal("UserPrefs5");
                var myBA:ByteArray = prefs.data.justTheBytes;
             var recoveredUPrefs:Object=myBA.readObject();

                var defaultTab:String=recoveredUPrefs["defaultTab"];
             txtOutput.text+= “default tab=”+defaultTab + “\n”;

                var visibleColumns:Object=recoveredUPrefs["visibleColumns"];
                 for (var elem:String in visibleColumns){
                   txtOutput.text+= elem+”=”+visibleColumns[elem]+ “\n”;
                 }
           }
               private function saveData():void{
                prefs = SharedObject.getLocal(“UserPrefs5″);

                var uPrefs:Object= new Object();
                var visibleCol:Object = new Object();
    //which col’s to make visible
    visibleCol["custName"]=”true”;
    visibleCol["custAddress"]=”false”;
    visibleCol["customerAge"]=”true”;
                uPrefs["visibleColumns"]=visibleCol;
                // which tab in TabNavigator has to be opened first
                uPrefs["defaultTab"]=”CanceledOrders”;
                // turning the object with prefs into a set of bytes
                var baPrefs:ByteArray = new ByteArray();
                baPrefs.writeObject(uPrefs);
                baPrefs.position = 0;

                // Saving the byte array on disk in a SharedObject
                prefs.data.justTheBytes=baPrefs;
                var flushStatus:String = null;   

                try {
   prefs.flush(COOKIE_SIZE);
                } catch (error:Error) {
                    trace(“Error…Could not write SharedObject to disk”+ error.message);
                }
           }     ]]>
 </mx:Script>
</mx:Application>

Press the button Save, and it’ll save the hardcoded preferences in a local shared object – a String called defaultTab and a collection of flags for visible columns.  Before saving, it serializes the Object (yes a simple Object with dynamically added properties) into an array of bytes and stores it in a local shared object.   If you want, you can pass this array to the backend for storage in the database.

Press the Read button, and the properties will be resurrected from the disk and added to the text area on the screen. Simple, elegant, and flexible.  Not exactly object-oriented. Sorry.

Yakov

Comments (4)

 

Grey Line

The book “RIA development with Adobe Flex and Java” is written. Check out the book site. Do you know why we are smiling? Because the writing is over! It took us longer than planned because we had to work for a living, and the time for writing this book was just stolen from our families and our sleep.

The book is about 650 pages, and here’s the brief TOC:

Foreword by Bruce Eckel
Foreword by Matt Chotin
Chapter 1. Architecture of RIA
Chapter 2. Introduction to Flex Framework
Chapter 3. Flex Builder Development Environment
Chapter 4. Learning Flex Through Applications
Chapter 5. A Complete Application with RPC Communications
Chapter 6. End-to-End Rapid Application Development
Chapter 7. How to write your own data services
Chapter 8. Enhancing and Extending Flex Controls
Chapter 9. Trees with Dynamic Data Population
Chapter 10. Working with Large Applications
Chapter 11. Data-Driven Approach To Flex Programming
Chapter 12. Application logging and debugging
Chapter 13. Building a SlideShow Application
Chapter 14. Developing Custom Charts
Chapter 15. Integration With External Applications
The book should be printed in February 2007. Most of the book is a heavy duty stuff that will be useful for any real-world Flex developer. The first four chapters go easy on you, but then we start going deep under the Flex 2 skin. We are sure that this book is going to be useful for any Flex practitioner. We hope that this book will be appreciated by Java developers, even though a reader with any object-oriented background will be able to use it.
This was my fourth book. And it’s the fourth time when I say, “Never again”. Let’s see if I’ll be able to keep the promise this time.

Yakov Fain

Comments (11)

 

Grey Line

In the last half year I worked with a number of enterprise developers getting in the Flex/RIA platform. In most cases it was not easy as they have certain set of rules of how things suppose to work that do not work any more.

It reminded me very similar experience of 15 years ago. Pleple where moving from mainframe/terminals based environment to the windows environment. Every design and workflow that worked great for 20 years needed to be reconsidered and improved. The screens were going fro 1/4MegaPixels to 3/4MegaPixels – huge jump opening new possibilities. Windowing and event-driven programming were going to change user experince forever.

These days my desktop is over 4MegaPixels and it takes me 5 seconds to drag mouse from  one corner to the other. I learned not to layer multiple windows on the top of each other and memorized shortcuts to get needed widgets at once. I am longing for “flat” with some overlays – or is it due to the fact I have been using Flex too much in the last 2 years?

Enterprise developers miss design guidelines to show the way RIA applications should look and behave. There was similar huge gap between lined notepads used to layout flat mainframe/terminal screens and plain interaction and WIMP wireframes. Simple books like Interface Guidelines were on every desk. I was not able to find the same type of book (not because of lack of trying) for Flex/RIA development – and it is needed very much every day.

I am answering countless questions like : “How do you make application flow with asynchronous message boxes?”. Well, I avoid message boxes by providing validation ques and inflow wizards that serve the same purpose – unobtrusively, ahead of time. The screens are neither flat browser page nor convoluted MDI but rather are scaled/structured based on user feedback/history. The concepts of proximity, personal preferences and simplicity take preference. All that is on the top of usuall Wall-street requirement of absolute top-speed – waisting time for nice animation is punishable offense. Anything that “moves” is potential target and a lot of Playstation concepts are at play here.

Cool pictures showing RIA’s “best practices” would worth thousand words. A book with words explaining along the patterns of user interaction would be priceless

Sincerely,

Anatole Tartakovsky

faratasystems.com

Comments (4)

 

Grey Line

WM_CLOSE, windowClosing, closeQuery… Which one is closer to your heart? One way or the other you
have to give your user that last chance to save modified data when he or she is closing the application
window. Providing the same functionality in Flex requires help on the JavaScript/HTML side, so this post
will illustrate two techniques in one example.

Preventing the user from closing the browser window has been traditionally done via onbeforeunload event.
Here is the snippet of JavaScript code, which, once you put it in
./html-template/index.template.html will (IE & Mozilla)

  1. resolve reference to Flash control;
  2. tentatively invoke ActionScript method getUnsavedDataWarning() ;
  3. force browser to popup the alert “Are you sure you want to navigate away? ….. OK/Cancel”; with your custom text in the middle:

<!– index.template.html –>
. . . . .
<script language=”JavaScript” type=”text/javascript”>
<!–
// Give user a chance to save modified data
window.onbeforeunload = function() {
var warning=”";
var fxControl = document.${application} || window.${application};
if (typeof fxControl.getUnsavedDataWarning==”function”) {
warning = fxControl.getUnsavedDataWarning();
}
if (warning!=”)
return warning;
else
return;
}
// –>
</script>
Now, all of this is in vain, of course, if your Flex application does not advertise the method
getUnsavedDataWarning(). And here is where Flash ExternalInterface API comes very handy. You can
expose any method: static, instance or anonymous, like the one below:

import flash.external.ExternalInterface;

private const UNSAVED_DATA_WARNING:String = ‘You have unsaved changes. You will lose them if you continue.’;

if ( ExternalInterface.available ) {
ExternalInterface.addCallback(
“getUnsavedDataWarning”,
function():String {
if (commitRequired) return UNSAVED_DATA_WARNING;
else return ”;
}
);
}

The complete MXML application is listed below. Do not forget to paste the JavaScript stuff in ./html-template/index.template.html:

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”
layout=”vertical” creationComplete=”onCreationComplete()”>
<mx:Script><![CDATA[

import flash.external.ExternalInterface;
private const UNSAVED_DATA_WARNING:String = 'You have unsaved changes. You will lose them if you continue.';
[Bindable] private var commitRequired:Boolean;

private function onCreationComplete():void {
if ( ExternalInterface.available ) {
ExternalInterface.addCallback(
“getUnsavedDataWarning”,
function():String {
if (commitRequired) return UNSAVED_DATA_WARNING;
else return ”;
}
);
}
}
]]></mx:Script>
<mx:Text text=”Type something below to test” />
<mx:TextInput id=”input” change=”commitRequired=(input.text!=”)”/>
<mx:Text text=”Close window and you will{commitRequired?’ ‘:’ not’} be prompted” />

</mx:Application>

WM_CLOSE, windowClosing, closeQuery, onbeforeunload… Tell me who your friends are … ; )

Victor

Comments (1)

 

Grey Line

I killed my morning listening to Adobe financial report published on December 14, 2006. What else can you do at 7AM on Saturday?

It proved what I wrote in my post a month ago. Adobe has great financial results, but Flex generated revenues were not there yet, which is fine for such a young tool as Flex 2. There is just one mentioning of the word Flex at the end of slide 17. Creative Suites products are fine. Acrobat is THE working horse. LiveCycle is the main bread winner in the enterprise sector. Flash Lite is doing great in mobile devices (phones and gaming).

If you listen to Q/A session (fast forward first three minutes if you are in a rush), it clearly states that Apollo is not expected to generate revenues in 2007. This is also understanable – Apollo has not been released yet. Flex was mentioned here as a path toward Apollo.

Twenty seventh minute into Q/A has yet another mentioning of Flex as a tool helping create Flash content.

The 30th minute – Apollo is for the future development leveraging development for existing formats such as PDF and SWF.
I do acknowledge the fact that Flex is a great tool, but as of today, Flex developers (myself included) are early adopters. We’ve gotten the Flex message a year earlier than the rest of the enterprise world. Stay put, improve your Flex skills, we are getting there. You’ll be able to monetize your skills in 2008.Big time.
Yakov Fain

Comments (8)

 

Grey Line

This was a five-week Adobe Flex evening class at New York University, one of the top-tier schools in the USA.

When I found out that eighty percent of my students were Java programmers, I decided to turn this class into an intensive training experience.
This was a hands-on class, plus students were working on their own on home works (complete working applications) between the sessions. For each class I’ve given 15-page custom-made handout, and here’s a quick summary of what I’ve covered:

Session 1. Architecture of Rich Internet Applications. Hands-n demo of an …AJAX application. Flex Builder. Development of a calculator.
Session 2. States, ActionScript, List-based controls, Data Binding – multiple use cases
Session 3. XML with E4X, Namespaces, Five different ways of programming in Flex depending on your background, Regular Expressions.
Session 4. Flex-JSP communication, Events, custom components
Session 5. A lab on custom events. Detailed code review of an application utilizing Flex remoting with RemoteObject, HTTPService

In the beginning of each class I’d ask students to stop me if I was moving too fast. They’d say, “We’re fine, go ahead”. At the end of the class students asked for the next, more advanced class. Universities do not add new classes to their programs too often, but NYU deserves lots of credits for being an early adopter of Adobe Flex 2. They did not include advanced class in their program yet, but I’ll re-run the same class in April. Re-run is a wrong word here, because I always teach something different. Money-wise, this class was an absolute bargain – only six hundred bucks for five evenings with me. Hmm, does it sound like a whore’s statement? Nope. Pretty Woman? Yakov, stop it, we are talking about EDUCATION here, get serious, will you! OK, OK. Sorry. No, just one more…singing…We do not need no education…Pink Floyd…

Beside NYU I’ll be co-teaching one day Flex Workshop at a famous AjaxWorld conference in March and private corporate gigs in the USA and Europe (btw, would love to go to India while it’s not too hot there). I’m also wondering if there is a huge demand in Adobe Certified Flex Instructors in Hawaii, Paris, Tokyo and Bangkok?
Yours truly,
Yakov Fain

Comments

 

Grey Line

What I love about Flex is that it is a framework. On top of library of the off-the-shelf controls which fits the bill for many of the Rich Internet Applications needs, Flex enables you to create new or extend existing components with a simplicity and elegance hardly ever offered by other GUI development systems. Here is an illustration of extending standard ComboBox component.How do you programmatically select a specific value in a ComboBox? Suppose the ComboBox is populated with array of states:

private var usStates:Array=[
    {label:"New York", data:"NY"},
    {Colorado", data:"CO"},
    {Texas", data:"TX"}
];
. . . . . . . .
   <mx:ComboBox id=”cbx_states” dataProvider=”{usStates}”/>
To force Texas to the visible portion of the ComboBox you can write the following index-fetching loop, comparing val against the label of each element of dataProvider:

var val:String; val= ’Texas’ ;
for (var i: int = 0; i < cbx.dataProdider.length; i++) {
    if ( val == cbx_states.dataProvider[i].label) {
      cbx_states.selectedIndex = i;
      break;
  }
}

Alternatively, you could look up the data of dataProvider’s elements :
var val:String; val= ‘TX’ ;
for (var i: int = 0; i < cbx.dataProdider.length; i++) {
    if ( val == cbx.dataProvider[i].data) {
      cbx_states.selectedIndex = i;
      break;
    }
}

Either way these index-fetching loops will clutter the application code instead of simple cbx_states.value=‘Texas’. But wait, there is value property: if a selected object has something in the data property, value refers to data, otherwise value refers to the label:mx.control.Alert.show(cbx_states.value); // displays ‘NY’

Alas, standard value is read-only. In the following part of the post we will turn value into a read-write property. Then index-fetching loops to modify the ComboBox selection will be history.

Let’s extend the original ComboBox so that derived class provides a special setter for the value property. The setter attempts to match the value with either data or label properties of the dataProvider. Once a match is found, it modifies the selectedIndex, which should cause the ComboBox to select the matching object:

<?xml version=”1.0″ encoding=”utf-8?>
<mx:ComboBox xmlns:mx=”http://www.adobe.com/2006/mxml” >
<mx:Script>
<![CDATA[
   public function set value(val:Object) : void {
    if ( val != null ) {
    for (var i : int = 0; i < dataProvider.length; i++) {
    if ( val == dataProvider[i].data || val == dataProvider[i].label) {
    selectedIndex = i;
    return;
    } } }
    selectedIndex = -1;
    }
 ]]>
<mx:Script>
<mx:ComboBox>

Listing 1. ComboBox.mxml – Making the value property writeable

If the ComboBox.mxml is located under the com/theriabook/controls, its test application can look as in Listing 2 below.

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” xmlns:fx=”com.theriabook.controls.*”>
   <mx:ArrayCollection id=”comboData”>
       <mx:Array>
           <mx:Object label=”New York” data=”NY”/>
           <mx:Object label=”Connecticut” data=”CT”/>
           <mx:Object label=”Illinois” data=”IL”/>
       </mx:Array>
   </mx:ArrayCollection>
   <mx:Label text=”Current bound value is ‘{cbx_1.value}’ ” />
   <fx:ComboBox id=”cbx_1″ value=”IL” width=”150″ dataProvider=”{comboData}”/>
<mx:Application>

Listing 2. Using our new ComboBox

Run this application, and you’ll see the ComboBox displaying the value New York… while we would expect Illinois. We forgot about the order in which objects’ properties (cbx_1) get initialized. In particular, the value property is initialized before the dataProvider. And, since during dataProvider initialization ComboBox, by default, selects the first item, the work performed by our value setter is wasted. You can prove the point by just trading places of value and dataProvider in the above application code.

Should I rely on the order of attributes in MXML components? Apparently not. Especially when Flex offers an excellent mechanism to coordinate the updates to multiple properties of the control – the commitProperties() method.

Here is how it works: whenever you need to modify a property raise some indicator, store the value in the temporary variable and call invalidateProperties(), like in the following snippet:

 private var candidateValue:Object;
 private var valueDirty:Boolean = false;
 public function set value(val:Object) : void {
   candidateValue = val;
   valueDirty = true;
   invalidateProperties();
   }

In response to invalidateProperties() Flex will guarantee a call of commitProperties() at a later time, so that all property changes deferred in the above manner can be consolidated in a single place and in the pre-determined order:

override protected function commitProperties():void {
    super.commitProperties();      if (dataProviderDirty) {
      super.dataProvider = candidateDataProvider;
      dataProviderDirty = false;
   }

   if (valueDirty) {
      applyValue(candidateValue);
      valueDirty = false;
   }
}

Aside of co-ordinating updates to different properties, this coding pattern helps to avoid multiple updates to the same property and, in general, allows setter methods to return faster, improving the overall performance of the control. The entire code of our “value-aware” ComboBox is presented in Listing 3:

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:ComboBox xmlns:mx=”http://www.adobe.com/2006/mxml”>
<mx:Script>
<![DATA[

   private var candidateValue:Object;
   private var valueDirty:Boolean = false;
   private var candidateDataProvider:Object;
   private var dataProviderDirty:Boolean = false;
   
   private function applyValue(val:Object):void {
       if ((val != null) && (dataProvider != null)) {
               
          for (var i : int = 0; i < dataProvider.length; i++) {
               if ( val == dataProvider[i].data || val == dataProvider[i].label) {
                  ;  selectedIndex = i;
                  ;  return;
       }    }    }
       selectedIndex = -1;
   }      public function set value(val:Object) : void {
       candidateValue = val;
       valueDirty = true;
       invalidateProperties();
   }
   override public function set dataProvider(value:Object):void {
       candidateDataProvider = value;
       dataProviderDirty = true;
       invalidateProperties();
   }

   override protected function commitProperties():void {
       super.commitProperties();

       if (dataProviderDirty) {
          super.dataProvider = candidateDataProvider;
          dataProviderDirty = false;
       }

       if (valueDirty) {
          applyValue(candidateValue);
          valueDirty = false;
       }
   }
   ]]>
<mx:Script>
<mx:ComboBox>

Listing 3. The value-aware ComboBox

Now everything works as expected. If you change the ComboBox selection, the top label, which initially contains Current bound value is “IL” will change accordingly. No miracles here, a regular Flex data binding one would say. Indeed, good things are easy to take for granted. Still, we have not provided any binding declarations or binding code in our ComboBox. So why does it work? It works because the original Flex definition of value getter ComboBox has already been marked with metadata tag [“Bindable”], which makes the property bindable (you do not have to have a setter to be bindable):

[Bindable("change")]
[Bindable("valueCommitted")]

But wait, you may say, these binding definitions contract us to trigger events change and valueCommitted. Yet our value setter does not contain a single dispatchEvent call. Where is the catch? Events are dispatched inside the code that assigns selectedIndex. This assignment results in invocation of selectedIndex setter, which ultimately dispatches events.

Remember, Flex is a framework.Read the code :)

Victor

Comments (7)

 

Grey Line

New York, December 7, 2006.  Victor and I will teach  an intensive, one-day workshop called “Adobe Flex  Developer Bootcamp” at at AJAXWorld 2007 (see http://www.ajaxworld.com/) in New York in March.

Our hands-on workshop is intended for Web developers and designers who want to learn how to build Rich Internet Application using Adobe Flex. Held on March 19, the day before the AJAXWorld Conference & Expo begins, Flex Developer Bootcamp is a hands-on workshop that is not offered anywhere else: during this day attendees will create two fully functional applications.
Pre-requisites: working knowledge of any object-oriented programming language. Having your own laptop is not required but helps.
Here’s brief description of the program.
Part 1, 4 hours. Overview of Adobe Flex architecture, major components, work with XML, data binding, events, remoting, and hands on work on an application that implement above components and techniques in an application that will use online live data feed.
Part 2, 4 hours. Rapid application development  of  database-centric applications in Flex. After covering the required artifacts, the workshop will include hands-on work on a  CRUD application, utilizing  advanced datagrid techniques.
We are also planning to offer the same program at a slower pace as a two or three day class.
Hope to see you there!
Yakov Fain
Adobe Certified Flex Instructor

Comments

 

Grey Line

I had been working on DataGrid that displays heterogenous data: any two rows may share all or just some of the properties, so the DataGrid appears sparse. Then during  “protecting” non-editable items per specific row this casting example popped up.

The easiest way to row-by-row disable editing is via itemEditBeginning event:

 mx:DataGrid itemBeginning=”onItemEditBeginning(event)” …

 public function onItemEditBeginning(event:DataGridEvent):void {
  if (event.itemRenderer) {
  // do something to determine whether item is editable, preventDefault otherwise
 }
}

Now let’s fantasize that items populating your dataProvider might be implementing IEditableItem, which mandates method isFieldEditable():

 function isFieldEditable(dataField:String):Boolean;

Then you can write something like

Variant1:
 var item:Object = event.itemRenderer.data ;
 if (item is IEditableItem) {
  if (!item.isFieldEditable(dataField)) {
   event.preventDefault();
  }
 }

OR – Variant2:
 var item:Object = event.itemRenderer.data ;
  if (item is IEditableItem) {
    if (!IEditableItem(item).isFieldEditable(dataField)) {
     event.preventDefault();
    }
  }

OR – Variant3:
 var item:IEditableItem = event.itemRenderer.data as IEditableItem;
 if (item) {
  if (!item.isFieldEditable(dataField)) {
     event.preventDefault();
  }
 }

Variant1 looks simple, but may cost you some sleep when another developer redefines IEditableItem, which won’t be discovered during compilation. Variant2 applies regular casting to take care of that potential re-factoring and … gets annoying with IEditableItem/IEditableItem. Variant 3 combines clarity of 1 with reliability of 3: when item is not IEditableItem “as” casting returns null, otherwise we are already strongly typed. Call it hair splitting and I won’t argue much. After all, this does the job too:

 if (typeof item["isFieldEditable"]==”function”) {
  if (!item["isFieldEditable"](dataField)) {
   event.preventDefault();
  }
 }

:)
Victor

Comments (1)

 

Grey Line

Unless your project is as simple as HelloWorld application, compilation and deployment of this application has to be automated. Creating a build script for any decent size application (i.e. hundreds of files in Flex and server-side Java) is a project on its own. Java programmers typically use one of the open source build tools such as Ant or Maven to formally describe and execute all steps required to build and deploy their projects.

If you did not have a chance to use any of the build tools before, this section is for you. This is a mini primer on how use Ant, a popular Java-based build tool from Apache.

Even deployment of such simple application as HelloWorld may consists of several steps, for example

1. Using mxmlc compile HelloWorld.mxml into swf file.
2. Create an HTML wrapper file(s) from one of the HTML templates.
3. Create or clean the directory in your Web server where HelloWorld files will be deployed.
4. Copy or ftp HelloWorld.swf and supporting files to this directory.

Now imagine that your HelloWorld application is a part of a larger application that includes Java modules that also need to be compiled and deployed under some server location. Deployment process of even a small size project usually involves at least a dozen of dependent tasks that have to be executed in a particular order. Creating and maintaining of a build script is well worth the effort

Building HelloWorld with Ant

With Ant, you describe your project in a build file written in xml (it’s typically called build.xml). An Ant project consists of targets (i.e. compile), which in turn consist of tasks (i.e. mkdir, exec). Listing below shows a build.xml that will create an output directory bin, and compile our HelloWorld application into this directory. This Ant build file has two targets: init and compile.

<project name=”HelloWorld” default=”compile”>
<property name=”flex.mxmlc” location=”C:\Program Files\Adobe\Flex Builder 2 Plug-in\Flex SDK 2\bin\mxmlc.exe” />
<property name=”dest.dir” value=”bin” />

<target name=”init”>
<delete dir=”${dest.dir}” />
<mkdir dir=”${dest.dir}” />
</target>

<target name=”compile” depends=”init”>
<exec executable=”${flex.mxmlc}” failonerror=”true”>
<arg line=”-output ‘${dest.dir}/HelloWorld.swf’”/>
<arg line=”HelloWorld.mxml”/>
</exec>
</target>
</project>

The init target consists of two tasks: delete and create the directory called bin.

The compile target will compile HelloWorld.mxml producing bin\HelloWorld.swf. If we’d need to manually write a command that compiles HelloWorld.mxml into the bin directory, it’d look like this:

mxmlc -output bin/HelloWorld.swf HelloWorld.mxml

Besides targets and tasks, our build.xml contains two property tags. One of them defines the property called dest.dir that has a value bin, which is the name of the output directory for our compiled HelloWorld.swf:

<property name=”dest.dir” value=”bin” />

This means that wherever Ant will encounter dest.dir surrounded with ${ and }, it’ll substitute it with the value of this property, which is bin in our case.

The above project also defines a property called flex.mxmlc that tells Ant where mxmlc compiler is located. The target compile uses Ant’s task exec, which will run mxmlc compiler passing it arguments specified in <arg> tags.

Let’s download Ant from http://ant.apache.org/. Installation is simple: just unzip the archive and add the path its bin directory (i.e. C:\apache-ant-1.6.5\bin) to the environment variable path of your OS.

Now we can open a command window, get into directory where HelloWorld.mxml and build.xml are located, and enter the command ant that will start the execution of the default target of our project, which is compile. But since compile target is marked as dependent on init, ant will execute the init target first.

Ant has extensive set of predefined tasks like copy, zip, jar, War, FTP, Mail, Condition, and many more described at Ant’s manual.

For example, to make our build file work in both Windows and Unix environments, we can specify the location of mxmlc compiler as follows:
<condition property=”flex.mxmlc” value=”${sdkdir}/bin/mxmlc”>
<os family=”unix”/>
</condition>
<condition property=”flex.mxmlc” value=”${sdkdir}/bin/mxmlc.exe”>
<os family=”windows”/>
</condition>

You can pass values of the properties from ant command line using –Dpropery=value option. For example, if we use the code snippet above, the property sdkdir can be passed from a command line:

ant –Dsdkdir=/opt/usr/freeflex

You can write more sophisticated ant scripts. For example, you can automate creation of an html wrapper for swf files with replaceregex task applied to one of the provided html templates. You can write build scripts that will merge Flex generated artifacts with Java Web applications. Automating builds with Ant can get you pretty far.

There are lots of online articles and books on Ant, but do not miss Ant in Anger by Steve Loughran, where he discusses some core practices, naming conventions and team development process with Ant.

Yakov

Comments (4)

 

Grey Line

Closure are one of the cornerstones of dynamic languages, and  most of the language features like OO or frameworks are using them as a foundation. At the same time, a formal definition of closures does not really help to understand them. Let us go through few examples. First, we’ll show what closures look like, and then we’ll give you their use patterns.

It all starts with the use of an anonymous function that has access to outer lexically scoped variables:

<?xml version=”1.0″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml
   layout=”vertical” creationComplete=”doInit(event)”>
<mx:Script>
import mx.controls.Alert;
private var greeting:String=”Hello”;
private function doInit(evt:Event) : void {
  btn.addEventListener(“click”, function(evt:Event):void {
  Alert.show( greeting + “, ” + txt.text);
 });
}
</mx:Script>
<mx:Button id=”btn” label=”closure” />
<mx:TextInput id=”txt”/>
</mx:Application>

Compile and run this code. Here’s an oversimplified three-part description of closures:
Closures are functions defined in one class or function context and passed to another object for execution at a latter time.
Closure’s “attachment” happens at run-time ( and can be executed multiple times during application run) and is just the stack-frame allocation where all the context variables (“greeting” in our case) are being saved for later use. In most cases it is surrounding variables of the hosting function and current run-time class instance.
Finally, the closure execution can happen at any time, and can also have parameters at the time of call. A standard convention is to have an “Event” object being passed in with the information from the calling object.

It seems you can use closures to “snapshot” any number of parameters. Unfortunately, it is true for some dynamic languages, but not for ECMA Script ones – ActionScript and JavaScript. Let us illustrate the difference with few examples. First, let us make sure that ActionScript closures are compile-time artifacts rather then true dynamic interpreted counterparts. First, let us swap the order of closure and greetings definition statements.

<?xml version=”1.0″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml
   layout=”vertical” creationComplete=”doInit(event)”>
<mx:Script>
import mx.controls.Alert;
private var myClosure :Function = function(evt:Event) {
  Alert.show( greeting + “, ” + txt.text);
 }
private function doInit(evt:Event) : void {
  btn.addEventListener(“click”, myClosure);
}
private var greeting:String=”Hello”;
</mx:Script>
<mx:Button id=”btn” label=”closure”/>
<mx:TextInput id=”txt”/>
</mx:Application>

It still works, even though “greeting” should have been undefined at the time of closure definition – proving that just reference is being used. Also, unlike in Java, the scope of an object is the stack-frame content of the enclosing function or a class. Here is example that would not compile in Java, but is perfectly legal in AS3:

private function aaa():void{
    { var a = 1; } //in Java a is not visible outside of the block
    Alert.show(a);
}
 Flash is a stack machine, a closure is a stack variable in the enclosing function, and this stack-frame approach greatly simplifies implementation of closures and code optimizers based on stack, even though requires some adjustments in the coding style. Another issue is that we do not have object values here – everything is done by reference. Let us replace greeting’s value right before the call:

<mx:Button label=”closure” click=”greeting=’good morning’”/>

As you can see, the greeting was replaced on alert screen with the new value – would not happen if “closure” would use greeting reference by value in the time of definition.

Closures is a primary feature of ActionScript. Every method in your class is a closure. That is how it knows instance variables of the class. Essentially every class is a big closure. You can write a function with closures inside that would be very much a class for all practical purposes.

Closures are unavoidable when you use asynchronous operations or need to process an event on the other object. Almost any non-trivial action in Flex – communication with the server or getting an input from user – is asynchronous. Using closure automatically gives you the reference to the class instance in which you have your function to the external object processing the event. That is sufficient for processing the asynchronous method’s results in most cases. Automatic pointing of “this” context to the instance defining the function greatly simplifies the coding as it is natural to the developer.

Prior to Flex 2, in Flex 1.5 developers were responsible for supplying context to the closure. Ability to replace closure context gives greater flexibility to the code making it truly dynamic.

The next code samples shows a closure on an arbitrary object to provide a custom context object:

public class Closure extends Object {
   public static function create(context:Object, func:Function, … pms):Function {
   var f:Function = function():*
   {
    var target:*  = arguments.callee.target;
    var func:*    = arguments.callee.func;
    var params:*  = arguments.callee.params;

    var len:Number = arguments.length;
    var args:Array = new Array(len);
    for(var i:Number=0; i < len; i++)
     args[i] = arguments[i];

    args["push"].apply(args, params);
    return func.apply(target, args);
   };

   var _f:Object = f;
   _f.target  = context;
   _f.func    = func;
   _f.params  = pms;
   return f;
  }
 }

The following code illustrates how to call this closure:

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute” creationComplete=”onCreationComplete(event)”>
<mx:Script>
 <![CDATA[
  import mx.controls.Alert;
  private var myClosure:Function ;
  private function onCreationComplete (evt:Event):void {
   myClosure = Closure.create({greeting:"Good evening"},function(name:String):void {
    Alert.show( this.greeting + ", " + name);
     },"world");
   var greeting:String;
   greeting ="Hello";
  }
 ]]>
</mx:Script>
<mx:Button id=”btn” label=”closure” click=”myClosure()”/>
</mx:Application>

Now, the alert shows “Good evening, world” because the method has been applied using different context. Often this methodology is called “delegation” and used by business frameworks to centralize processing of certain events.

The above example illustrates the relationship between context, functions and closures. Using this technique allows you to implement dynamic inheritance, polymorphism  and other OO concepts.

Comments (3)

 

Grey Line

Ted Patrick has written a blog called 10 Signs you need to join the FlexComponents List. I like Ted’s list, but here’s my version.

1. You’ve read a book on object-oriented programming and think that you understand the difference between inheritance and composition.
2. Your boss likes this little thingy that you’ve included on the Customers screen and wants to see the same functionality on the Invoice window.
3. You sincerely believe that you are the only one who knows how to create an auto-complete text field and can make money by selling Flex components
4. Your girlfriend comes home late on Wednesdays saying that she is developing Flex components with her college room mate, you do not know what it is but smell something fishy.
5. You want to prove that you can create a button that will broadcast an event to whoever wants to listen, and an enclosing application will receive it!
6. Your college professor gave you the homework to write Flex component
7. You are a naive college graduate and still believe that cut-and-paste is bad and writing reusable code is possible even thought your dad said that it’s BS.
8. It’s raining outside, and you don’t have money to fill the tank of your car to drive to the supermarket and get some beer to think about something more exciting than writing Flex components.
9. You truly believe that any framework will tie your hands and hurt your creativity, and just using self-contained components is a way to go.
10. You want to earn respect in the Flex community.

Homework. To turn this list into a component reusable for all languages/technologies, do the following:

1. Put this list into into a data collection
2. Introduce two bindable variables and use them in the list above:
[Bindable]
var tool:String=”Java”;
[Bindable]
var evangelist:String=”Joe Smith”;
3. Compile this component into an swc file
4. Create a sample application that has two TextInput fields, a list and a button, so the user can enter the language and evangelist’s name of their choice.
5. Deploy the swc as an RSL and explain pros and cons of this approach.

Yakov Fain
Adobe Certified Flex Instructor

Comments