<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:thr="http://purl.org/syndication/thread/1.0">
  <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/building-an-enterprise-framewo.html" />
  <link rel="self" type="application/atom+xml" href="http://www.insideria.com/atom.xml" />
  <id>tag:www.insideria.com,2009://34/tag:www.insideria.com,2009://34.36126-</id>
  <updated>2009-11-16T15:01:58Z</updated>
  <title>Comments for Building an Enterprise Framework - Enterprise Development with Flex, Part 2 (http://www.insideria.com/2009/05/building-an-enterprise-framewo.html)</title>
  <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>
  <entry>
    <id>tag:www.insideria.com,2009://34.36126</id>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/building-an-enterprise-framewo.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blogs.oreilly.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=34/entry_id=36126" title="Building an Enterprise Framework - Enterprise Development with Flex, Part 2" />
    <published>2009-05-13T14:00:42Z</published>
    <updated>2009-05-14T21:10:11Z</updated>
    <title>Building an Enterprise Framework - Enterprise Development with Flex, Part 2</title>
    <summary>Note: This is excerpted from Chapter 3 of the Rough Cuts version of Enterprise Development with Flex. This book is still in progress, and you can get access to it now. Get the Enterprise Development with Flex Rough Cut Rough...</summary>
    <author>
      <name>Yakov Fain</name>
      
    </author>
    
    <category term="Features" />
    
    <content type="html" xml:lang="en" xml:base="http://www.insideria.com/">
      <![CDATA[<p><em>Note: This is excerpted from Chapter 3 of the <a href="http://oreilly.com/roughcuts/faq.csp" target="_blank">Rough Cuts</a> version of <a href="http://oreilly.com/catalog/9780596801014/">Enterprise Development with Flex</a>. This book is still in progress, and you can <a href="http://my.safaribooksonline.com/9780596801465?cid=orm-cat-readnow-9780596801465" target="_blank">get access to it now</a>.</em></p>

<div class="ap_r_front"><img src="http://oreilly.com/catalog/covers/9780596801014_cat.gif" alt="Enterprise Development with Flex cover" style="width: 148px;" /><div class="apcaption"><a href="http://oreilly.com/catalog/9780596801014/">Get the Enterprise Development with Flex Rough Cut</a></div></div>

<p><em><a href="http://www.oreilly.com/roughcuts">Rough Cuts</a> is a service from Safari Books Online that gives you early access to content on cutting-edge technologies -- before it's published.  It lets you literally read the book as it is being written. </em></p>

<p>Check out <a href="http://www.insideria.com/2009/05/chapter-preview-building-an-en.html" target="_blank">Part 1</a> of this chapter.</p>

<p><b>Table of Contents, Part 2</b></p>
<p><span class="sect2"><a href=
"#the_base_class_for_resources">The Base Class for
Resources</a></span></p>
<p><span class="sect2"><a href=
"#datagrid_with_resources">DataGrid with
Resources</a></span></p>
<p><span class="sect1"><a href="#data_forms">Data
Forms</a></span></p>
<p><span class="sect2"><a href=
"#the_dataform_component">The DataForm
Component</a></span></p>
<p><span class="sect2"><a href=
"#the_dataformitem_component">The DataFormItem
Component</a></span></p>

<h3 class="title"><a name="the_base_class_for_resources" id=
"the_base_class_for_resources"></a>The Base Class for
Resources</h3>

<p><a href="#class_resourcebase" title=
"Example&nbsp;3.11.&nbsp;Class ResourceBase">Example&nbsp;3.11,
&ldquo;Class ResourceBase&rdquo;</a> depicts the class <code class=
"literal">ResourceBase</code>, which serves as a base class for all
resources for all components. This class can tell properties from
styles. In Chapter&nbsp;2,
<i>Selected Design Patterns</i> you learned about a class
factory that accepts a class or a function name to create instances
of objects. We applied that same technique here: With <code class=
"literal">ResourceBase</code>, resource instance can be created
from a class factory or a class.</p>
<p>Technically, the <code class="literal">ResourceBase</code> class
applies specified values as either properties or resources.</p>
<a name="class_resourcebase" id=
"class_resourcebase"></a>

<p class="title"><b>Example&nbsp;3.11.&nbsp;Class
ResourceBase</b></p>

<pre style="height: 600px;"><code><span class="bold"><strong>package</strong></span> com.farata.resources {
    <span class="bold"><strong>import</strong></span> com.farata.controls.TextInput;

    <span class="bold"><strong>import</strong></span> flash.system.ApplicationDomain;

    <span class="bold"><strong>import</strong></span> mx.core.ClassFactory;
    <span class="bold"><strong>import</strong></span> mx.core.UIComponent;
    <span class="bold"><strong>import</strong></span> mx.utils.StringUtil;

    <span class="bold"><strong>public dynamic class</strong></span> ResourceBase {
          <span class="bold"><strong>public var</strong></span> resourceProps:Array = [];
          <span class="bold"><strong>public var</strong></span> resourceStyles:Array = [];

    <span class="bold"><strong>public function</strong></span> load(source:Object):<span class="bold"><strong>void</strong></span> {
          <span class="bold"><strong>for each</strong></span>(<span class="bold"><strong>var</strong></span> propName:String <span class="bold"><strong>in</strong></span> resourceProps) {
               <span class="bold"><strong>try</strong></span>   {
                     <span class="bold"><strong>if</strong></span>( source[propName])
                          <span class="bold"><strong>this</strong></span>[propName]= source[propName] ;
               }
               <span class="bold"><strong>catch</strong></span> (e:Error) {}
          }
          <span class="bold"><strong>for each</strong></span>(<span class="bold"><strong>var</strong></span> styleName:String <span class="bold"><strong>in</strong></span> resourceStyles){
               <span class="bold"><strong>try</strong></span>   {
                     <span class="bold"><strong>if</strong></span>(source.getStyle(styleName))
                          <span class="bold"><strong>this</strong></span>[styleName] = source.getStyle(styleName);
               }
               <span class="bold"><strong>catch</strong></span> (e:Error){}
          }
    }

    <span class="bold"><strong>public function</strong></span> apply(target:Object):<span class="bold"><strong>void</strong></span>               {
          <span class="bold"><strong>try</strong></span> {
               <span class="bold"><strong>for each</strong></span>(<span class="bold"><strong>var</strong></span> propName:String <span class="bold"><strong>in</strong></span> resourceProps)
                     <span class="bold"><strong>if</strong></span> (<span class="bold"><strong>this</strong></span>[propName]!=<span class="bold"><strong>undefined</strong></span>)
                          target[propName] = <span class="bold"><strong>this</strong></span>[propName];
          } <span class="bold"><strong>catch</strong></span> (e:Error) {
               <span class="bold"><strong>var</strong></span> error:String = mx.utils.StringUtil.substitute(
            <span class="bold"><strong>"Incompatible resource class. Can not apply</strong></span>
             <span class="bold"><strong>property {0} of {1} to {2}"</strong></span>,
              [propName,<span class="bold"><strong>this</strong></span>.toString(), target.toString()] );
             <span class="bold"><strong>throw new</strong></span> Error(error);
          }
          <span class="bold"><strong>try</strong></span> {

               <span class="bold"><strong>for each</strong></span>(<span class="bold"><strong>var</strong></span> styleName:String <span class="bold"><strong>in</strong></span> resourceStyles)
                     <span class="bold"><strong>if</strong></span>(<span class="bold"><strong>this</strong></span>[styleName])
                          target.setStyle(styleName, <span class="bold"><strong>this</strong></span>[styleName]);
    }

    <span class="bold"><strong>public static function</strong></span> getResourceInstance(value:Object,
                                styleOwner:Object=<span class="bold"><strong>null</strong></span>):*   {
          <span class="bold"><strong>var</strong></span> resClass:Object;
          <span class="bold"><strong>if</strong></span>(value <span class="bold"><strong>is</strong></span> Class) {
               resClass = Class(value);
               <span class="bold"><strong>if</strong></span> (styleOwner) {
                     <span class="bold"><strong>try</strong></span>  {
                          <span class="bold"><strong>var</strong></span> result:* = <span class="bold"><strong>new</strong></span> resClass(styleOwner);
                          <span class="bold"><strong>return</strong></span> result;
                     }
                     <span class="bold"><strong>catch</strong></span> (e:Error) {
                          <span class="bold"><strong>return new</strong></span> resClass();
                     }
               }
               <span class="bold"><strong>else</strong></span>
                     <span class="bold"><strong>return new</strong></span> resClass();
          }
          <span class="bold"><strong>else if</strong></span>(value <span class="bold"><strong>is</strong></span> ResourceBase)
               <span class="bold"><strong>return</strong></span> value;
          <span class="bold"><strong>else if</strong></span>(value <span class="bold"><strong>is</strong></span> ClassFactory)
               <span class="bold"><strong>return</strong></span> ClassFactory(value).newInstance();
          <span class="bold"><strong>else</strong></span>  <span class="bold"><strong>if</strong></span> (value != <span class="bold"><strong>null</strong></span>)   {
               <span class="bold"><strong>var</strong></span> v:String = String(value).replace(/{/,<span class="bold"><strong>""</strong></span>);
               v = v.replace(/}/,<span class="bold"><strong>""</strong></span>);
               resClass = ApplicationDomain.currentDomain.getDefinition(v);
               <span class="bold"><strong>if</strong></span> (styleOwner) {
                     <span class="bold"><strong>try</strong></span>  {
                          <span class="bold"><strong>var</strong></span> result2:* = <span class="bold"><strong>new</strong></span> resClass(styleOwner);
                          <span class="bold"><strong>return</strong></span> result2;
                     }
                     <span class="bold"><strong>catch</strong></span> (e:Error) {
                          <span class="bold"><strong>return new</strong></span> resClass();
                     }
               }
               <span class="bold"><strong>else</strong></span>
                     <span class="bold"><strong>return new</strong></span> resClass();
          }
    }
    <span class="bold"><strong>public function get</strong></span> itemEditor() : UIComponent {
          <span class="bold"><strong>return new</strong></span> TextInput();
    }
}
}
</code></pre> 

<br class="example-break" />

<p>When application programmers design a resource for a particular
type of Flex UI control, they simply extend it from a <code class=
"literal">ResourceBase</code> class (or build a MXML component
based on it) and specify the names of the variables and their
default values, if need be.</p>
<p>The <code class="literal">ResourceBase</code> class relies on
two arrays: <code class="literal">resourceProps</code> and
<code class="literal">resourceStyles</code>. When application
developers create concrete resources, they also must populate these
arrays. <a href="#sample_comboboxresource" title=
"Example&nbsp;3.12.&nbsp;Sample ComboBoxResource">Example&nbsp;3.12,
&ldquo;Sample ComboBoxResource&rdquo;</a> illustrates
implementation of a sample class called <code class=
"literal">ComboBoxResource</code>. Note how the array <code class=
"literal">resourceProps</code> is populated with the data in the
constructor.</p>

<a name="sample_comboboxresource" id=
"sample_comboboxresource"></a>
<p class="title"><b>Example&nbsp;3.12.&nbsp;Sample
ComboBoxResource</b></p>

<pre><code><span class="bold"><strong>package</strong></span> com.farata.resources {
    <span class="bold"><strong>import</strong></span> mx.core.IFactory;
    <span class="bold"><strong>import</strong></span> mx.core.UIComponent;
    <span class="bold"><strong>import</strong></span> mx.styles.CSSStyleDeclaration;
    <span class="bold"><strong>import</strong></span> mx.styles.StyleManager;
    <span class="bold"><strong>import</strong></span> com.farata.controls.ComboBox;

    <span class="bold"><strong>dynamic public class</strong></span> ComboBoxResource <span class="bold"><strong>extends</strong></span> ResourceBase {
          <span class="bold"><strong>public var</strong></span> autoFill :Boolean = <span class="bold"><strong>false</strong></span>;
          <span class="bold"><strong>public var</strong></span> keyField : String = <span class="bold"><strong>"data"</strong></span>;
          <span class="bold"><strong>public var</strong></span> destination:String=<span class="bold"><strong>null</strong></span>;
          <span class="bold"><strong>public var</strong></span> dropdownWidth : int = 0;
          <span class="bold"><strong>public var</strong></span> editable:Boolean = <span class="bold"><strong>false</strong></span>;
          <span class="bold"><strong>public var</strong></span> itemRenderer:IFactory = <span class="bold"><strong>null</strong></span>;
          <span class="bold"><strong>public var</strong></span> labelFunction : Function = <span class="bold"><strong>null</strong></span>;
          <span class="bold"><strong>public var</strong></span> labelField : String = <span class="bold"><strong>"label"</strong></span>;
          <span class="bold"><strong>public var</strong></span> dataField : String = <span class="bold"><strong>"label"</strong></span>;
          <span class="bold"><strong>public var</strong></span> method : String = <span class="bold"><strong>null</strong></span>;
          <span class="bold"><strong>public var</strong></span> width:int=&minus;1;
          <span class="bold"><strong>public var</strong></span> dataProvider : Object;

          <span class="bold"><strong>public function</strong></span> ComboBoxResource(styleOwner:Object=<span class="bold"><strong>null</strong></span>) {
               resourceProps.push(<span class="bold"><strong>"autoFill"</strong></span>, <span class="bold"><strong>"keyField"</strong></span>, <span class="bold"><strong>"destination"</strong></span>,
              <span class="bold"><strong>"dropdownWidth"</strong></span>, <span class="bold"><strong>"editable"</strong></span>,<span class="bold"><strong>"itemRenderer"</strong></span>, <span class="bold"><strong>"labelField"</strong></span>,
             <span class="bold"><strong>"labelFunction"</strong></span>,<span class="bold"><strong>"method"</strong></span>, <span class="bold"><strong>"dataProvider"</strong></span>, <span class="bold"><strong>"width"</strong></span>);

               <span class="bold"><strong>var</strong></span> sd:CSSStyleDeclaration =
                  StyleManager.getStyleDeclaration(<span class="bold"><strong>".comboBoxResource"</strong></span>);
               <span class="bold"><strong>if</strong></span> (!sd)        {
                     sd = <span class="bold"><strong>new</strong></span> CSSStyleDeclaration();
                     StyleManager.setStyleDeclaration(<span class="bold"><strong>".comboBoxResource"</strong></span>,
                   sd, <span class="bold"><strong>false</strong></span>);
                     sd.setStyle(<span class="bold"><strong>"paddingBottom"</strong></span>, 0);
                     sd.setStyle(<span class="bold"><strong>"paddingTop"</strong></span>, 0);
               }
               <span class="bold"><strong>if</strong></span> ( styleOwner!= <span class="bold"><strong>null</strong></span> )
                     load( styleOwner );
          }
          <span class="bold"><strong>override public function get</strong></span> itemEditor() :UIComponent {
                     <span class="bold"><strong>return new</strong></span> ComboBox();
          }
    }
}
</code></pre> 

<br class="example-break" />
<p>This class has to be written once for your enterprise framework,
and after that any junior programmer can easily create and update
resources such as <code class=
"literal">DepartmentComboResource</code> or <code class=
"literal">StateComboResource</code> shown earlier in this chapter
in <a href="http://www.insideria.com/2009/05/chapter-preview-building-an-en.html#statecomboboxresource_with" title=
"Example&nbsp;3.9.&nbsp;StateComboBoxResource with hard-coded states">
Example&nbsp;3.9, &ldquo;StateComboBoxResource with hard-coded
states&rdquo;</a> and <a href=
"http://www.insideria.com/2009/05/chapter-preview-building-an-en.html#sample_departmentcomboreso" title=
"Example&nbsp;3.10.&nbsp;Sample DepartmentComboResource configured for a remote destination">
Example&nbsp;3.10, &ldquo;Sample DepartmentComboResource configured
for a remote destination&rdquo;</a>.</p>
<p>Similarly to CSS, resources should be compiled into a separate
SWF file. They can be loaded and reloaded during the runtime, and
you can find out more about class loaders in Chapter 7.</p>

<h3 class="title"><a name="datagrid_with_resources" id=
"datagrid_with_resources"></a>DataGrid with Resources</h3>

<p>The most interesting part about these resources is that you can
attach them not only to regular, but also to such dynamic controls
as <code class="literal">DataGridColumn</code>. For example, the
next code snippet instructs the <code class=
"literal">DataGridColumn</code> (it was also enhanced and is
available in clear.swc) to turn itself into a <code class=
"literal">ComboBox</code> and populate itself based on the
configured resource <code class=
"literal">DepartmentComboResource</code> shown in <a href=
"http://www.insideria.com/2009/05/chapter-preview-building-an-en.html#statecomboboxresource_with" title=
"Example&nbsp;3.9.&nbsp;StateComboBoxResource with hard-coded states">
Example&nbsp;3.9, &ldquo;StateComboBoxResource with hard-coded
states&rdquo;</a>.</p>
<a name="I_programlisting3_d1e9577" id=
"I_programlisting3_d1e9577"></a>
<pre><code>&lt;fx:DataGridColumn dataField="DEPT_ID" editable="false"
headerText="Department"
<span class="bold"><strong>resource="{com.farata.resources.DepartmentComboResource}"/&gt;</strong></span>
</code></pre> 
<p>A resource attached to a <code class=
"literal">DataGridColumn</code> not only sets a column's properties
but also identifies the item renderer and editor for this
column.</p>
<p>As discussed in Chapter&nbsp;2, <i>Selected Design Patterns</i>, class factories become
extremely powerful if you use them as item renderer for a data grid
column. Using this methodology, you can also encapsulate a number
of properties and styles in the object provided by the factory. For
example, you can enable the support of resources on the enhanced
<code class="literal">DataGridColumn</code> object by adding the
code fragment in <a href="#enabling_resources_support"
title=
"Example&nbsp;3.13.&nbsp;Enabling resources support in DataGridColumn">
Example&nbsp;3.13, &ldquo;Enabling resources support in
DataGridColumn&rdquo;</a>:</p>
<a name="enabling_resources_support" id=
"enabling_resources_support"></a>
<p class="title"><b>Example&nbsp;3.13.&nbsp;Enabling resources
support in DataGridColumn</b></p>

<pre style="height: 600px;"><code><span class="bold"><strong>private var</strong></span> _resource:Object;
        <span class="bold"><strong>public function set</strong></span> resource(value:Object):<span class="bold"><strong>void</strong></span>{
          _resource = ResourceBase.getResourceInstance(value, <span class="bold"><strong>this</strong></span>);
               <span class="bold"><strong>if</strong></span>(labelFunction==<span class="bold"><strong>null</strong></span>) {
                     getLabelFunctionByResource(_resource, <span class="bold"><strong>this</strong></span>);
               }
        }

        <span class="bold"><strong>public function get</strong></span> resource():Object{
          <span class="bold"><strong>return</strong></span> _resource;
        }
<span class="bold"><strong>        public static function</strong></span> getLabelFunctionByResource(resourceRef:Object,
                                                      column:Object):<span class="bold"><strong>void</strong></span> {
               <span class="bold"><strong>var</strong></span> resource:ResourceBase = resourceRef <span class="bold"><strong>as</strong></span> ResourceBase;
               <span class="bold"><strong>if</strong></span> (resource) {
                     <span class="bold"><strong>if</strong></span>(resource.hasOwnProperty(<span class="bold"><strong>"destination"</strong></span>) &amp;&amp;
                                                 resource[<span class="bold"><strong>"destination"</strong></span>])
                          CollectionUtils.getCollection(
                                <span class="bold"><strong>function</strong></span>(ev:Event, collection:Object):<span class="bold"><strong>void</strong></span> {
                                     collectionLoaded(collection, column);
                                },
                                resource.destination,
                                resource.method
                          );
                     <span class="bold"><strong>else if</strong></span> (resource.hasOwnProperty(<span class="bold"><strong>"dataProvider"</strong></span>) &amp;&amp;
                                              resource[<span class="bold"><strong>"dataProvider"</strong></span>]) {
                          collectionLoaded(
                                resource.dataProvider,
                                column,
                                safeGetProperty(resource, <span class="bold"><strong>"labelField"</strong></span>, <span class="bold"><strong>"label"</strong></span>),
                                safeGetProperty(resource, <span class="bold"><strong>"keyField"</strong></span>, <span class="bold"><strong>"data"</strong></span>)
                          );
                     }
               }
          }
          <span class="bold"><strong>private static function</strong></span> collectionLoaded(collection:Object, column:Object,
                          labelField:String = <span class="bold"><strong>null</strong></span>, dataField:String = <span class="bold"><strong>null</strong></span>):
<span class="bold"><strong>void</strong></span> {
               <span class="bold"><strong>if</strong></span> (<span class="bold"><strong>null</strong></span> == collection) <span class="bold"><strong>return</strong></span>;
               labelField =
                     labelField ?
                          labelField :
                          (column[<span class="bold"><strong>"labelField"</strong></span>] != <span class="bold"><strong>null</strong></span> ?
                                column.labelField :
                                (column.resource.labelField ?
                                     column.resource.labelField : <span class="bold"><strong>"label"</strong></span>));

               <span class="bold"><strong>if</strong></span> (!dataField)
                     dataField = column.resource.keyField ?
                                     column.resource.keyField : column.dataField;

               collection = CollectionUtils.toCollection(collection);

               <span class="bold"><strong>const</strong></span> options:Dictionary = <span class="bold"><strong>new</strong></span> Dictionary();

               <span class=
"emphasis"><em>// copy only when collection is non empty</em></span>
               <span class="bold"><strong>if</strong></span> (collection != <span class="bold"><strong>null</strong></span> &amp;&amp; collection.length &gt; 0 ) {
                     <span class="bold"><strong>const</strong></span> cursor:IViewCursor = collection.createCursor();
                     <span class="bold"><strong>do</strong></span> {
                          options[cursor.current[dataField]] =
                                                   cursor.current[labelField];
                     } <span class="bold"><strong>while</strong></span>(cursor.moveNext())
               }

               column.labelFunction = <span class="bold"><strong>function</strong></span>(data:Object, col:Object):String {
                     <span class="bold"><strong>var</strong></span> key:* = data <span class="bold"><strong>is</strong></span> String || data <span class="bold"><strong>is</strong></span> Number ? data :
                                                            data[col.dataField];
                     <span class="bold"><strong>var</strong></span> res:String = options[key];
                     <span class="bold"><strong>return</strong></span> res != <span class="bold"><strong>null</strong></span> ? res : <span class="bold"><strong>''</strong></span> + key;
               };
          }
</code></pre> 
<br class="example-break" />
<p>Suppose you have a <code class="literal">DataGrid</code> and a
<code class="literal">ComboBox</code> with the values 1, 2, and 3
that should be displayed as John, Paul, and Mary. These values are
asynchronously retrieved from a remote DBMS. You can't be sure,
however, if John, Paul, and Mary will arrive before or after the
<code class="literal">DataGrid</code> getst populated. The code
above extends the <code class="literal">DataGridColumn</code> with
the property <code class="literal">resource</code> and checks if
the application developer supplied a <code class=
"literal">labelFunction</code>. If not, the code tries to "figure
out" the <code class="literal">labelFunction</code> from the
resource itself.</p>
<p>If resource has the <code class="literal">destination</code> set
and the <code class="literal">method</code> is defined as in
<code class="literal">DepartmentComboResource</code> in <a href=
"http://www.insideria.com/2009/05/chapter-preview-building-an-en.html#statecomboboxresource_with" title=
"Example&nbsp;3.9.&nbsp;StateComboBoxResource with hard-coded states">
Example&nbsp;3.9, &ldquo;StateComboBoxResource with hard-coded
states&rdquo;</a>, the code loads the <code class=
"literal">Collection</code> and after that, it creates the
<code class="literal">labelFunction</code> (see <code class=
"literal">collectionLoaded()</code> method) based on the loaded
data.</p>
<p>The resource may either come with a populated <code class=
"literal">dataProvider</code> as in <a href=
"http://www.insideria.com/2009/05/chapter-preview-building-an-en.html#a_checkbox_resource" title=
"Example&nbsp;3.8.&nbsp;A CheckBox resource">Example&nbsp;3.8,
&ldquo;A CheckBox resource&rdquo;</a>, or the data for the
<code class="literal">dataProvider</code> may be loaded from the
server. When the <code class="literal">dataProvider</code> is
populated, the <code class="literal">collectionLoaded()</code>
method examines the <code class="literal">dataProvider</code>'s
data and creates the <code class="literal">labelFunction</code>.
The following code attaches a <code class=
"literal">labelFunction</code> on the fly as a dynamic function
that gets the data and by the key finds the <code class=
"literal">text</code> to display on the grid.</p>
<a name="I_programlisting3_d1e9842" id=
"I_programlisting3_d1e9842"></a>
<pre><code>column.labelFunction = <span class="bold"><strong>function</strong></span>(data:Object, col:Object):String {
          <span class="bold"><strong>var</strong></span> key:* = data <span class="bold"><strong>is</strong></span> String || data <span class="bold"><strong>is</strong></span> Number ? data :
                                               data[col.dataField];
                         <span class="bold"><strong>var</strong></span> res:String = options[key];
          <span class="bold"><strong>return</strong></span> res != <span class="bold"><strong>null</strong></span> ? res : <span class="bold"><strong>''</strong></span> + key;
     };
</code></pre> 
<p>This closure uses the dictionary <code class=
"literal">options</code> defined outside. The code above this
closure traverses the data provider and creates the following
entries in the dictionary:</p>
<p>1, John</p>
<p>2, Paul</p>
<p>3, Mary</p>
<p>Hence the value of the <code class="literal">res</code> returned
by this label function will be John, Paul, or Mary.</p>
<p>These few lines of code provide a generic solution for the
real-life situations that benefit from having asynchronously loaded
code tables that can be programmed by junior developers. This code
works the same way translating the <code class=
"literal">data</code> value into John and Mary, Alaska and
Pennsylvania, or department names.</p>

<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
<h3 class="title">Note</h3>
<p>With resources, the properties and styles of UI controls become
available not only to developers who write these classes, but to
outsiders in a similar to CSS fashion. The examples of resources
from the previous section clearly show that they are self-contained
easy to understand artifacts that can be used by anyone as a
business style sheets.</p>
</div>

<p>You can create a resource as a collection of styles, properties,
event listeners that also allow providing a class name to be used
with it. You can also create a class factory that will be producing
instances of such resources.</p>
<p>Technically, any resource is an abstract class factory that can
play the same role as XML-based configurable properties play in the
Java EE world. But this solution requires compilation and linkage
of all resources, which makes it closer to configuring Java objects
using annotations. Just to remind you, in Flex, CSS also get
compiled.</p>
<p>To summarize, resources offer the following advantages:</p>

<ul type="disc">
<li>
<p>They are compiled and work fast.</p>
</li>
<li>
<p>Because they are simple to understand, junior programmers can
work with them.</p>
</li>
<li>
<p>You can inherit one resource from another, and Flex Builder will
offer you context-sensitive help and Flex compiler will help you to
identify data type errors.</p>
</li>
<li>
<p>You can attach resources to a <code class=
"literal">DataGridColumn</code> and use them as a replacement of
item renderers.</p>
</li>
</ul>

<p>Resources are a good start for automation of programming. In
Chapter 6, you'll get familiar with yet another useful Flex
component called <code class="literal">DataCollection</code>, a
hybrid of <code class="literal">ArrayCollection</code> and
<code class="literal">RemoteObject</code>, which yet another step
toward reducing manual programming.</p>

<h2 class="title"><a name="data_forms" id=
"data_forms"></a>Data Forms</h2>

<p>In this section you'll continue adding components to the
enterprise framework. It's hard to find an enterprise application
that does not use forms, which makes the Flex Form component a
perfect candidate for possible enhancements. Each form has some
underlying model object, and the form elements are bound to the
data fields in the model. Flex 3 supports only one-way data
binding: Changes on <span class="underline">a</span> form
automatically propagate to the fields in the data model. But if you
<span class="underline">wanted</span> to update the form when the
data model changes, you <span class="underline">had</span> to
manually program it using the curly braces syntax in one direction
and <code class="literal">BindingUtils.bindProperty()</code> in
another.</p>
<p>Flex 4 introduces new feature: two-way binding. Add an @ sign to
the binding expression <code class="literal">@{expression}</code>
and notifications about data modifications <span class=
"underline">are</span> sent in both directions<span class=
"underline">&mdash;</span>from form to the model and back.
<span class="underline">Although</span> this helps in basic cases
where a text field on the form is bound to a text property in a
model object, two-way binding has not much use if you'd like to use
data types other than <code class="literal">String</code>.</p>
<p>For example, two-way binding won't help that much in forms that
use standard Flex <code class="literal">&lt;mx:CheckBox&gt;</code>
component. What are you going to bind here? The server side
application has to receive 1 if the <code class=
"literal">CheckBox</code> was selected and 0 if not. You can't just
bind its property <code class="literal">selected</code> to a
numeric data property on the underlying object. To really
appreciate two-way binding, you need to use different set of
components, similar to the ones that you have been building in this
chapter.</p>
<p>Binding does not work in cases when the model is a moving
target. Consider a typical master-detail scenario: The user
double-clicks on a row in a <code class="literal">DataGrid</code>
and details about selected row are displayed in a form. Back in Chapter&nbsp;1,
<i>Comparing Selected Flex Frameworks</i> you saw an example of
this: Doubling-clicking a grid row in Figure&nbsp;1.19, &ldquo;Removing the filter to keep generated Java
code&rdquo; opened up a form that displayed details of the
employee selected in a grid. This magic was done with the enhanced
form component that you are about to review.</p>
<p>The scenario with binding a form to a datagrid row has to deal
with a moving model; the user selects another row. Now what? The
binding source is different now and you need to think of another
way of refreshing the form data.</p>
<p>When you define data binding using an elegant and simple
notation with curly braces, the compiler generates additional code
to support it. But in the end, an implementation of the
<span class="emphasis"><em>Observer</em></span> design pattern is
needed, and "someone" has to write the code to dispatch events to
notify registered dependents when the property in the object
changes. In Java, this someone is a programmer, in Flex it's the
compiler that also registered event listeners with the model.</p>
<p>Flex offers the <code class="literal">Form</code> class that an
application programmer bind to an object representing the data
model. The user changes the data in the UI form, and the model gets
changed too. But the original <code class="literal">Form</code>
implementation does not have means of tracking the data
changes.</p>
<p>It would be nice if the <code class="literal">Form</code>
control (bound to its model of type a <code class=
"literal">DataCollection</code>) could support similar
functionality, with automatic tracking of all changes compatible
with <code class="literal">ChangeObject</code> class that is
implemented with remote data service. Implementing such
functionality is the first of the enhancements you'll make.</p>
<p>The second improvement belongs to the domain of data validation.
The enhanced data form should be smart enough to be able to
validate not just individual form items, but the form in its
entirety too. The data form should offer an API for storing and
accessing its validators <span class=
"emphasis"><em>inside</em></span> the form rather than in an
external global object. This way the form becomes a self-contained
black box that has everything it needs. (For details of what can be
improved in the validation process, see the section called
&ldquo;Validation&rdquo;.)</p>
<p>During the initial interviewing of business users, software
developers should be able to quickly create layouts to demonstrate
and approve the raw functionality without waiting for designers to
come up with the proper pixel-perfect controls and layouts.</p>
<p>Hence, your third target will be making the prototyping of the
views developer friendly. Beside the need to have uniform controls,
software developers working on prototypes would appreciate if they
should not be required to give definitive answers as to which
control to put on the data form. The first cut of the form may use
a <code class="literal">TextInput</code> control, but the next
version should use a <code class="literal">ComboBox</code> instead.
You want to come up with some UI-neutral creature (call it a
<span class="emphasis"><em>data form item</em></span>) that will
allow not be specific, like, "I'm a <code class=
"literal">TextInput</code>", or "I'm a <code class=
"literal">ComboBox</code>". Instead, developers will be able to
create prototypes with generic data items with easily attachable
resources.</p>

<h3 class="title"><a name="the_dataform_component" id=
"the_dataform_component"></a>The DataForm Component</h3>

<p>The solution that addresses your three improvements is a new
component called <code class="literal">DataForm</code> (<a href=
"#class_dataform" title=
"Example&nbsp;3.14.&nbsp;Class DataForm">Example&nbsp;3.14,
&ldquo;Class DataForm&rdquo;</a>). It's a subclass of a Flex
<code class="literal">Form</code>, and its code implements two-way
binding and includes a new property <code class=
"literal">dataProvider</code>. Its function <code class=
"literal">validateAll()</code>supports data validation explained in
the next sections. This <code class="literal">DataForm</code>
component will properly respond to data changes propagating them to
its data provider.</p>
<a name="class_dataform" id=
"class_dataform"></a>
<p class="title"><b>Example&nbsp;3.14.&nbsp;Class DataForm</b></p>

<pre style="height: 600px;"><code><span class="bold"><strong>package</strong></span> com.farata.controls{
<span class="bold"><strong>import</strong></span> com.farata.controls.dataFormClasses.DataFormItem;

<span class="bold"><strong>import</strong></span> flash.events.Event;

<span class="bold"><strong>import</strong></span> mx.collections.ArrayCollection;
<span class="bold"><strong>import</strong></span> mx.collections.ICollectionView;
<span class="bold"><strong>import</strong></span> mx.collections.XMLListCollection;
<span class="bold"><strong>import</strong></span> mx.containers.Form;
<span class="bold"><strong>import</strong></span> mx.core.Container;
<span class="bold"><strong>import</strong></span> mx.core.mx_internal;
<span class="bold"><strong>import</strong></span> mx.events.CollectionEvent;
<span class="bold"><strong>import</strong></span> mx.events.FlexEvent;
<span class="bold"><strong>import</strong></span> mx.events.ValidationResultEvent;

<span class="bold"><strong>public dynamic class</strong></span> DataForm <span class="bold"><strong>extends</strong></span> Form{
    <span class="bold"><strong>use namespace</strong></span> mx_internal;
    <span class="bold"><strong>private var</strong></span> _initialized:Boolean = <span class="bold"><strong>false</strong></span>;
    <span class="bold"><strong>private var</strong></span> _readOnly:Boolean = <span class="bold"><strong>false</strong></span>;
    <span class="bold"><strong>private var</strong></span> _readOnlySet:Boolean = <span class="bold"><strong>false</strong></span>;

    <span class="bold"><strong>public function</strong></span> DataForm(){
          <span class="bold"><strong>super</strong></span>();
          addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
    }

    <span class="bold"><strong>private var</strong></span> collection:ICollectionView;
    <span class="bold"><strong>public function get</strong></span> validators() :Array {
          <span class="bold"><strong>var</strong></span> _validators :Array = [];
          <span class="bold"><strong>for each</strong></span>(<span class="bold"><strong>var</strong></span> item:DataFormItem <span class="bold"><strong>in</strong></span> items)
               <span class="bold"><strong>for</strong></span> (<span class="bold"><strong>var</strong></span> i:int=0; i &lt; item.validators.length;i++)    {
                     _validators.push(item.validators[i]);
               }
          <span class="bold"><strong>return</strong></span> _validators;
    }
    <span class="bold"><strong>public function</strong></span> validateAll(suppressEvents:Boolean=<span class="bold"><strong>false</strong></span>):Array {
          <span class="bold"><strong>var</strong></span> _validators :Array = validators;
          <span class="bold"><strong>var</strong></span> data:Object = collection[0];
          <span class="bold"><strong>var</strong></span> result:Array = [];
          <span class="bold"><strong>for</strong></span> (<span class="bold"><strong>var</strong></span> i:int=0; i &lt; _validators.length;i++) {
               <span class="bold"><strong>if</strong></span> ( _validators[i].enabled ) {
                     <span class="bold"><strong>var</strong></span> v : * = _validators[i].validate(data, suppressEvents);
                     <span class="bold"><strong>if</strong></span> ( v.type != ValidationResultEvent.VALID)
                          result.push( v );
               }
          }
          <span class="bold"><strong>return</strong></span> result;
    }
[<span class="bold"><strong>Bindable</strong></span>(<span class="bold"><strong>"collectionChange"</strong></span>)]
    [<span class="bold"><strong>Inspectable</strong></span>(category=<span class="bold"><strong>"Data"</strong></span>, defaultValue=<span class="bold"><strong>"undefined"</strong></span>)]

    /**
     *  The dataProvider property sets of data to be displayed in the form.
     *  This property lets you use most types of objects as data providers.
     */
    <span class="bold"><strong>public function get</strong></span> dataProvider():Object{
          <span class="bold"><strong>return</strong></span> collection;
    }

    <span class="bold"><strong>public function set</strong></span> dataProvider(value:Object):<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>if</strong></span> (collection){
               collection.removeEventListener(CollectionEvent.COLLECTION_CHANGE,
                                                       collectionChangeHandler);
          }

          <span class="bold"><strong>if</strong></span> (value <span class="bold"><strong>is</strong></span> Array){
               collection = <span class="bold"><strong>new</strong></span>  ArrayCollection(value <span class="bold"><strong>as</strong></span> Array);
          }
          <span class="bold"><strong>else if</strong></span> (value <span class="bold"><strong>is</strong></span> ICollectionView){
               collection = ICollectionView(value);
          }
          <span class="bold"><strong>else if</strong></span> (value <span class="bold"><strong>is</strong></span> XML){
               <span class="bold"><strong>var</strong></span> xl:XMLList = <span class="bold"><strong>new</strong></span> XMLList();
               xl += value;
               collection = <span class="bold"><strong>new</strong></span> XMLListCollection(xl);
          }
          <span class="bold"><strong>else</strong></span>{
               // convert it to an array containing this one item
               <span class="bold"><strong>var</strong></span> tmp:Array = [];
               <span class="bold"><strong>if</strong></span> (value != <span class="bold"><strong>null</strong></span>)
               tmp.push(value);
               collection = <span class="bold"><strong>new</strong></span> ArrayCollection(tmp);
          }

          collection.addEventListener(CollectionEvent.COLLECTION_CHANGE,
                                               collectionChangeHandler);
          <span class="bold"><strong>if</strong></span>(initialized)
               distributeData();
    }

    <span class="bold"><strong>public function set</strong></span> readOnly(f:Boolean):<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>if</strong></span>( _readOnly==f ) <span class="bold"><strong>return</strong></span>;
          _readOnly = f;
          _readOnlySet = <span class="bold"><strong>true</strong></span>;
          commitReadOnly();
    }

    <span class="bold"><strong>public function get</strong></span> readOnly():Boolean{
          <span class="bold"><strong>return</strong></span> _readOnly;
    }

     /**
     *  This function handles CollectionEvents dispatched from the data provider
     *  as the data changes.
     *  Updates the renderers, selected indices and scrollbars as needed.
     *
     *  @param event The CollectionEvent.
     */
    <span class="bold"><strong>protected function</strong></span> collectionChangeHandler(event:Event):<span class="bold"><strong>void</strong></span>{
          distributeData();
    }

    <span class="bold"><strong>private function</strong></span> commitReadOnly():<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>if</strong></span>( !_readOnlySet ) <span class="bold"><strong>return</strong></span>;
          <span class="bold"><strong>if</strong></span>( !_initialized ) <span class="bold"><strong>return</strong></span>;
          _readOnlySet = <span class="bold"><strong>false</strong></span>;
          <span class="bold"><strong>for each</strong></span>(<span class="bold"><strong>var</strong></span> item:DataFormItem <span class="bold"><strong>in</strong></span> items)
               item.readOnly = _readOnly;
    }

    <span class="bold"><strong>private function</strong></span> distributeData():<span class="bold"><strong>void</strong></span> {
          <span class="bold"><strong>if</strong></span>((collection != <span class="bold"><strong>null</strong></span>) &amp;&amp; (collection.length &gt; 0)) {
               <span class="bold"><strong>for</strong></span> (<span class="bold"><strong>var</strong></span> i:int=0; i&lt;items.length; i++)       {
                     DataFormItem(items[i]).data = <span class="bold"><strong>this</strong></span>.collection[0];
               }
          }
    }

    <span class="bold"><strong>private var</strong></span> items:Array = <span class="bold"><strong>new</strong></span> Array();
    <span class="bold"><strong>private function</strong></span> creationCompleteHandler(evt:Event):<span class="bold"><strong>void</strong></span>{
          distributeData();
          commitReadOnly();
    }

    <span class="bold"><strong>override protected function</strong></span> createChildren():<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>super</strong></span>.createChildren();
          enumerateChildren(<span class="bold"><strong>this</strong></span>);
          _initialized = <span class="bold"><strong>true</strong></span>;
          commitReadOnly();
    }
    <span class="bold"><strong>private function</strong></span> enumerateChildren(parent:Object):<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>if</strong></span>(parent <span class="bold"><strong>is</strong></span> DataFormItem){
               items.push(parent);
          }
          <span class="bold"><strong>if</strong></span>(parent <span class="bold"><strong>is</strong></span> Container){
               <span class="bold"><strong>var</strong></span> children:Array = parent.getChildren();
               <span class="bold"><strong>for</strong></span>(<span class="bold"><strong>var</strong></span> i:int = 0; i &lt; children.length; i++){
                     enumerateChildren(children[i]);
               }
          }
    }
 }
}
</code></pre> 
<br class="example-break" />
<p>Let's walk through the code of the class <code class=
"literal">DataForm</code>. Examine the setter <code class=
"literal">dataProvider</code> in the code above. It always wraps up
the provided data into a collection. This is needed to ensure that
the <code class="literal">DataForm</code> supports working with
remote data services the same way as <code class=
"literal">DataGrid</code> does. It checks the data type of the
value. It wraps an <code class="literal">Array</code> into an
<code class="literal">ArrayCollection</code>, and XML turns into
<code class="literal">XMLListCollection</code>. If you need to
change the backing collection that stores the data of a form, just
point the collection variable at the new data.</p>
<p>If a single object is given as a <code class=
"literal">dataProvider</code>, turn it into a one-element array and
then into a collection object. A good example of such case is an
instance of a <code class="literal">Model</code>, which is an
<code class="literal">ObjectProxy</code> (see Chapter&nbsp;2,
<i>Selected Design Patterns</i>) that knows how to dispatch
events about changes of its properties.</p>
<p>Once in a while, application developers need to render
non-editable forms, hence the <code class="literal">DataForm</code>
class defines the <code class="literal">readOnly</code>
property.</p>
<p>The changes of the underlying data are propagated to the form in
the method <code class="literal">collectionChangeHandler()</code>.
The data can be modified either in the <code class=
"literal">dataProvider</code> on from the UI and the <code class=
"literal">DataForm</code> ensures that each visible <code class=
"literal">DataFormItem</code> object (<code class=
"literal">items[i]</code>) knows about it. This is done in the
function <code class="literal">distributeData()</code>:</p>
<a name="I_programlisting3_d1e10487" id=
"I_programlisting3_d1e10487"></a>
<pre><code>private function distributeData():void {
          if((collection != null) &amp;&amp; (collection.length &gt; 0)) {
               for (var i:int=0; i&lt;items.length; i++)       {
                     DataFormItem(items[i]).data = this.collection[0];
               }
          }
    }
</code></pre> 
<p>This code always works with the element zero of the collection,
because the form has always one object with data that is bound to
the form. Such a design resembles the functionality of the
<code class="literal">data</code> variable of the Flex <code class=
"literal">DataGrid</code> that for each column provides a reference
to the object that represents the entire row.</p>
<p>Again, we need the data to be wrapped into a collection to
support <code class="literal">DataCollection</code> or <code class=
"literal">DataService</code> from LCDS.</p>
<p>Technically, a <code class="literal">DataForm</code> class is a
<code class="literal">VBox</code> that lays out its children
vertically in two columns and automatically aligns the labels of
the form items. This <code class="literal">DataForm</code> needs to
allow nesting &ndash; containing items that are also instances of
the <code class="literal">DataForm</code> object. A recursive
function <code class="literal">enumerateChildren()</code> loops
through the children of the form, and if it finds a <code class=
"literal">DataFormItem</code>, it just adds it to the array
<code class="literal">items</code>. But if the child is a
container, the function loops through its children and adds them to
the same <code class="literal">items</code> array. In the end, the
property <code class="literal">items</code> contains all
<code class="literal">DataFormItems</code> that have to be
populated.</p>
<p>Notice that the function <code class=
"literal">validateAll()</code>is encapsulated inside the
<code class="literal">DataForm</code>, while in Flex framework is
located in the class <code class="literal">Validator</code>. There,
the validation functionality was external to <code class=
"literal">Form</code> elements and you'd need to give an array of
validators that were tightly coupled with specific form fields.</p>
<p>Our <code class="literal">DataForm</code> component is self
sufficient &ndash; its validators are embedded inside and reusing
the same form in different views or applications is easier
comparing to original Flex <code class="literal">Form</code> object
that relies on external validators.</p>

<h3 class="title"><a name="the_dataformitem_component" id=
"the_dataformitem_component"></a>The DataFormItem Component</h3>

<p>The <code class="literal">DataFormItem</code>, an extension of
Flex <code class="literal">FormItem</code>, is the next component
of the framework. This component should be a bit more humble than
its ancestor though. The <code class="literal">DataFormItem</code>
should not know too much about its representation and should be
able to render any UI component. Design of new Flex 4 components
has also been shifted toward separation between their UI and
functionality.</p>
<p>At least a half of the controls on a typical form are text
fields. Some of them use masks to enter formatted values like phone
numbers. The rest of the form items most likely are nothing else
but check boxes, and radio buttons. For these controls (and
whatever else you may need) just use resources. Forms also use
combo boxes. The "<a href="#datagrid_with_resources"
title="DataGrid with Resources">the section called &ldquo;DataGrid
with Resources&rdquo;</a>" section showned you how class factory
based resources can be used to place combo boxes and other
components inside the <code class="literal">DataGrid</code>. Now
you'll see how to enable forms to have flexible form items using
the same technique.</p>
<p>The <code class="literal">DataFormItem</code> is a binding
object that is created for each control placed inside the
<code class="literal">DataForm</code>. It has somewhat similar to
<code class="literal">BindingUtils</code> functionality to support
two-way binding and resolves circular references. The <code class=
"literal">DataFormItem</code> has two major functions:</p>

<ul type="disc">
<li>
<p>Attach an individual control inside to the instance of
<code class="literal">DataFormItemEditor</code> to listen to the
changes in the underlying control.</p>
</li>
<li>
<p>Create a UI control (either a default one, or according to
requested masked input or resource).</p>
</li>
</ul>

<p>The first function requires the <code class=
"literal">DataFormItem</code> control to support the syntax of
encapsulating other controls as it's implemented in <code class=
"literal">FormItem</code>, for example:</p>
<a name="I_programlisting3_d1e10614" id=
"I_programlisting3_d1e10614"></a>
<pre><code>&lt;lib:DataFormItem dataField="EMP_ID" label="Emp Id:"&gt;
  &lt;mx:TextInput/&gt;
&lt;/lib:DataFormItem&gt;
</code></pre> 
<p>In this case the <code class="literal">DataFormItem</code>
performs binding functions; in Flex framework, <code class=
"literal">&lt;mx:FormItem&gt;</code> would set or get the value in
the encapsulated UI component, but now the <code class=
"literal">DataFormItem</code> will perform the binding duties.
Assignment of any object to the <code class=
"literal">dataField</code> property item of the <code class=
"literal">DataFormItem</code> will automatically pass this value to
the enclosed components. If, say an application developer decides
to use a chart as a form item, the data assigned to the
<code class="literal">DataFormItem</code> will be given for
processing to the chart object. The point is that application
developers would use this control in a uniform way regardless of
what object is encapsulated in the <code class=
"literal">DataFormItem</code>.</p>
<p>The second function, creating a UI control, is implemented with
the help of resources, which not only allow specifying the styling
of the component, but also can define what component to use. If you
go back to the code of the class <code class=
"literal">ResourceBase</code>, you'll find there a getter
<code class="literal">itemEditor</code> that can be used for
creation of controls. Actually, this gives you two flexible ways of
creating controls for the form: either specify a resource name, or
specify a component as <code class=
"literal">itemEditor=myCustomComponent</code>. If none of these
ways is engaged a default <code class="literal">TextInput</code>
control will de created.</p>
<p>The code above looks somewhat similar to the original
<code class="literal">FormItem</code>, but it adds new powerful
properties to the component that represents form item. The data of
the form item is stored in the <code class="literal">EMP_ID</code>
property of the data collection specified in the <code class=
"literal">dataProvider</code> of the <code class=
"literal">DataForm</code>. The <code class="literal">label</code>
property plays the same role as in <code class=
"literal">FormItem</code>.</p>
<p>The source code of the <code class="literal">DataFormItem</code>
component is shown in <a href="#class_dataformitem" title=
"Example&nbsp;3.15.&nbsp;Class DataFormItem">Example&nbsp;3.15,
&ldquo;Class DataFormItem&rdquo;</a>. It starts with defining
properties as in <code class="literal">DataGrid</code> &ndash;
<code class="literal">dataField</code>, <code class=
"literal">valueName</code> and <code class=
"literal">itemEditor</code>. The <code class=
"literal">DataGridItem</code> can create an <code class=
"literal">itemEditor</code> from a <code class=
"literal">String</code>, an <code class="literal">Object</code> or
a class factory. It also defines an array <code class=
"literal">validator</code> that will be described later in this
chapter.</p>
<a name="class_dataformitem" id=
"class_dataformitem"></a>
<p class="title"><b>Example&nbsp;3.15.&nbsp;Class
DataFormItem</b></p>

<pre style="height: 600px;"><code><span class="bold"><strong>package</strong></span> com.farata.controls.dataFormClasses {
    <span class="bold"><strong>import</strong></span> com.farata.controls.DataForm;
    <span class="bold"><strong>import</strong></span> csom.farata.controls.MaskedInput;
    <span class="bold"><strong>import</strong></span> com.farata.core.UIClassFactory;
    <span class="bold"><strong>import</strong></span> com.farata.resources.ResourceBase;
    <span class="bold"><strong>import</strong></span> com.farata.validators.ValidationRule;

    <span class="bold"><strong>import</strong></span> flash.display.DisplayObject;
    <span class="bold"><strong>import</strong></span> flash.events.Event;
    <span class="bold"><strong>import</strong></span> flash.events.IEventDispatcher;
    <span class="bold"><strong>import</strong></span> flash.utils.getDefinitionByName;

    <span class="bold"><strong>import</strong></span> mx.containers.FormItem;
    <span class="bold"><strong>import</strong></span> mx.events.FlexEvent;
    <span class="bold"><strong>import</strong></span> mx.validators.Validator;

    <span class="bold"><strong>dynamic public class</strong></span> DataFormItem <span class="bold"><strong>extends</strong></span> FormItem {
          <span class="bold"><strong>public function</strong></span> DataFormItem()    {
               <span class="bold"><strong>super</strong></span>();
          }

        <span class="bold"><strong>private var</strong></span> _itemEditor:IEventDispatcher; //DataFormItemEditor;

        [<span class="bold"><strong>Bindable</strong></span>(<span class="bold"><strong>"itemEditorChanged"</strong></span>)]
        [<span class="bold"><strong>Inspectable</strong></span>(category=<span class="bold"><strong>"Other"</strong></span>)]
        mx_internal <span class="bold"><strong>var</strong></span> owner:DataForm;

        <span class="bold"><strong>private var</strong></span> _dataField:String;
        <span class="bold"><strong>private var</strong></span> _dataFieldAssigned:Boolean = <span class="bold"><strong>false</strong></span>;
        <span class="bold"><strong>private var</strong></span> _labelAssigned:Boolean = <span class="bold"><strong>false</strong></span>;
        <span class="bold"><strong>private var</strong></span> _valueName:String = <span class="bold"><strong>null</strong></span>;
        <span class="bold"><strong>private var</strong></span> _readOnly:Boolean = <span class="bold"><strong>false</strong></span>;
        <span class="bold"><strong>private var</strong></span> _readOnlySet:Boolean = <span class="bold"><strong>false</strong></span>;

        <span class="bold"><strong>public function set</strong></span> readOnly(f:Boolean):<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>if</strong></span>( _readOnly==f ) <span class="bold"><strong>return</strong></span>;
          _readOnly = f;
          _readOnlySet = <span class="bold"><strong>true</strong></span>;
          commitReadOnly();
         }

        <span class="bold"><strong>public function get</strong></span> readOnly():Boolean {
          <span class="bold"><strong>return</strong></span> _readOnly;
        }

        <span class="bold"><strong>public function set</strong></span> dataField(value:String):<span class="bold"><strong>void</strong></span>{
          _dataField = value;
          _dataFieldAssigned = <span class="bold"><strong>true</strong></span>;
        }

        <span class="bold"><strong>public function get</strong></span> dataField():String{
          <span class="bold"><strong>return</strong></span> _dataField;
        }

        <span class="bold"><strong>override public function set</strong></span> label(value:String):<span class="bold"><strong>void</strong></span> {
          <span class="bold"><strong>super</strong></span>.label = value;
          _labelAssigned = <span class="bold"><strong>true</strong></span>;
        }

        <span class="bold"><strong>public function set</strong></span> valueName(value:String):<span class="bold"><strong>void</strong></span>{
          _valueName = value;
          }

        <span class="bold"><strong>public function get</strong></span> valueName():String {
          <span class="bold"><strong>return</strong></span> _valueName;
        }

        <span class="bold"><strong>override public function set</strong></span> data(value:Object):<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>super</strong></span>.data = value;
          <span class="bold"><strong>if</strong></span>(_itemEditor)
               <span class="bold"><strong>if</strong></span> (_itemEditor[<span class="bold"><strong>"data"</strong></span>] != value[_dataField])
                     _itemEditor[<span class="bold"><strong>"data"</strong></span>] = value[_dataField];

               <span class="bold"><strong>for</strong></span> ( <span class="bold"><strong>var</strong></span> i : int = 0; i &lt; validators.length; i++) {
                     <span class="bold"><strong>if</strong></span> ( validators[i] <span class="bold"><strong>is</strong></span> ValidationRule &amp;&amp; data)
                          validators[i][<span class="bold"><strong>"data"</strong></span>]= data;
                     validators[i].validate();
               }
        }

        <span class="bold"><strong>override protected function</strong></span> createChildren():<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>super</strong></span>.createChildren();
          <span class="bold"><strong>if</strong></span>(<span class="bold"><strong>this</strong></span>.getChildren().length &gt; 0) {
               _itemEditor = <span class="bold"><strong>new</strong></span> DataFormItemEditor(<span class="bold"><strong>this</strong></span>.getChildAt(0), <span class="bold"><strong>this</strong></span>);
               _itemEditor.addEventListener(Event.CHANGE, dataChangeHandler);
               _itemEditor.addEventListener(FlexEvent.VALUE_COMMIT,
                                                          dataChangeHandler);
              }
        }

        <span class="bold"><strong>public function get</strong></span> itemEditor():Object {
          <span class="bold"><strong>return</strong></span> _itemEditor;
        }

        <span class="bold"><strong>private var</strong></span> _validators :Array = [];

        <span class="bold"><strong>public function get</strong></span> validators() :Array {
               <span class="bold"><strong>return</strong></span> _validators;
          }
          <span class="bold"><strong>public function set</strong></span> validators(val :Array ): <span class="bold"><strong>void</strong></span> {
               _validators = val;
          }

        <span class="bold"><strong>public var</strong></span> _dirtyItemEditor:Object;

        <span class="bold"><strong>public function set</strong></span> itemEditor(value:Object):<span class="bold"><strong>void</strong></span>{
               _dirtyItemEditor = <span class="bold"><strong>null</strong></span>;
         <span class="bold"><strong>if</strong></span>(value <span class="bold"><strong>is</strong></span> String){
                <span class="bold"><strong>var</strong></span> clazz:Class = Class(getDefinitionByName(value <span class="bold"><strong>as</strong></span> String));
            _dirtyItemEditor = <span class="bold"><strong>new</strong></span> clazz();
          }
          <span class="bold"><strong>if</strong></span>(value <span class="bold"><strong>is</strong></span> Class)
               _dirtyItemEditor = <span class="bold"><strong>new</strong></span> value();
          <span class="bold"><strong>if</strong></span>(value <span class="bold"><strong>is</strong></span> UIClassFactory)
               _dirtyItemEditor = value.newInstance();
          <span class="bold"><strong>if</strong></span>(value <span class="bold"><strong>is</strong></span> DisplayObject)
               _dirtyItemEditor = value;
       }

       <span class="bold"><strong>private function</strong></span> dataChangeHandler(evt:Event):<span class="bold"><strong>void</strong></span>{
               <span class="bold"><strong>if</strong></span> (evt.target[<span class="bold"><strong>"data"</strong></span>]!==<span class="bold"><strong>undefined</strong></span>)  {
                     <span class="bold"><strong>if</strong></span> (data != <span class="bold"><strong>null</strong></span>) {
                     data[_dataField] = evt.target[<span class="bold"><strong>"data"</strong></span>];
                     }
               }
          }

        <span class="bold"><strong>private var</strong></span> _resource:Object;
        <span class="bold"><strong>public function set</strong></span> resource(value:Object):<span class="bold"><strong>void</strong></span>{
          _resource = ResourceBase.getResourceInstance(value);
          invalidateProperties();
        }

        <span class="bold"><strong>public function get</strong></span> resource():Object{
          <span class="bold"><strong>return</strong></span> _resource;
        }

        <span class="bold"><strong>private function</strong></span> commitReadOnly():<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>if</strong></span>( _itemEditor==<span class="bold"><strong>null</strong></span> ) <span class="bold"><strong>return</strong></span>;
          <span class="bold"><strong>if</strong></span>( !_readOnlySet ) <span class="bold"><strong>return</strong></span>;
          <span class="bold"><strong>if</strong></span>( Object(_itemEditor).hasOwnProperty(<span class="bold"><strong>"readOnly"</strong></span>) )
          {
               Object(_itemEditor).readOnly = _readOnly;
               _readOnlySet = <span class="bold"><strong>false</strong></span>;
          }
        }

        <span class="bold"><strong>override protected function</strong></span> commitProperties():<span class="bold"><strong>void</strong></span>{
          <span class="bold"><strong>super</strong></span>.commitProperties();
          <span class="bold"><strong>if</strong></span>(itemEditor == <span class="bold"><strong>null</strong></span>) //no child controls and no editor from resource
          {
                     <span class="bold"><strong>var</strong></span> control:Object = _dirtyItemEditor;
                     <span class="bold"><strong>if</strong></span>(!control &amp;&amp; getChildren().length &gt; 0)
                          control = getChildAt(0);  //user placed control inside
                     <span class="bold"><strong>if</strong></span>(!control)
                          control = <span class="bold"><strong>i</strong></span>temEditorFactory(resource <span class="bold"><strong>as</strong></span> ResourceBase);

                     <span class="bold"><strong>if</strong></span>(resource)
                          resource.apply(control);
                     <span class="bold"><strong>if</strong></span>( (control <span class="bold"><strong>is</strong></span> MaskedInput) &amp;&amp; hasOwnProperty
(<span class="bold"><strong>"formatString"</strong></span>))
                          control.inputMask = <span class="bold"><strong>this</strong></span>[<span class="bold"><strong>"formatString"</strong></span>];

                     addChild(DisplayObject(control));
                     //Binding wrapper to move data back and force
                     _itemEditor = <span class="bold"><strong>new</strong></span>
                            DataFormItemEditor(DisplayObject(control),<span class="bold"><strong>this</strong></span>);
                     _itemEditor.addEventListener(Event.CHANGE, dataChangeHandler);
                     _itemEditor.addEventListener(FlexEvent.VALUE_COMMIT,
                                                          dataChangeHandler);
              } <span class="bold"><strong>else</strong></span>
               control = itemEditor.dataSourceObject;

         commitReadOnly();

          <span class="bold"><strong>for</strong></span> ( <span class="bold"><strong>var</strong></span> i : int = 0; i &lt; validators.length; i++) {
               <span class="bold"><strong>var</strong></span> validator : Validator = validators[i] <span class="bold"><strong>as</strong></span> Validator;
               validator.property = (_itemEditor <span class="bold"><strong>as</strong></span> DataFormItemEditor).valueName;
               validator.source = control;
               <span class="bold"><strong>if</strong></span> ( validator <span class="bold"><strong>is</strong></span> ValidationRule &amp;&amp; data)
                     validator[<span class="bold"><strong>"data"</strong></span>]= data;
               validator.validate();
          }
        }
          protected function itemEditorFactory(resource : ResourceBase =
                                                         null):Object{
               var result:Object = null;
               if (resource &amp;&amp; ! type)
                     result = resource.itemEditor;
               else {
                     switch(type)    {
                     case "checkbox":
                          result = new CheckBox();
                          if (!resource) {
                                resource = new CheckBoxResource(this);
                                resource.apply(result);
                          }
                          break;
                     case "radiobutton":
                          result = new RadioButtonGroupBox();
                          if (!resource) {
                                resource = new RadioButtonGroupBoxResource(this);
                                resource.apply(result);
                          }
                          break;
                     case "combobox":
                          result = new ComboBox();
                          if (!resource) {
                                resource = new ComboBoxResource(this);
                                resource.apply(result);
                          }
                          break;
                     case "date":
                          result = new DateField();
                          if (formatString) (result as DateField).formatString =
                                                                  formatString;
                          break;
                     case "datetime":
                          result = new DateTimeField();
                          if (formatString) (result as DateTimeField).formatString =
                                                                  formatString;
                          break;
                     case "mask":
                          result = new MaskedInput();
                          break;
                     }
               }
               if(result == null &amp;&amp; formatString)
                     result = guessControlFromFormat(formatString);
               if(result == null)
                     result = new TextInput();
               return result;
          }

          protected function guessControlFromFormat(format:String):Object{
               var result:Object = null;
               if(format.toLowerCase().indexOf("currency") != &minus;1)
                     result = new NumericInput();
               else if(format.toLowerCase().indexOf("date") != &minus;1){
                     result = new DateField();
                     (result as DateField).formatString = format;
               }
               else{
                     result = new MaskedInput();
                     (result as MaskedInput).inputMask = format;
               }
               return result;
          }
    }
}
</code></pre> 
<br class="example-break" />
<p>Read the code above, and you'll see that you can use an instance
of a <code class="literal">String</code>, an <code class=
"literal">Object</code>, a class factory or a UI control as an
<code class="literal">itemEditor</code> property of the
<code class="literal">DataFormItem</code>. The function
<code class="literal">createChildren()</code> adds event listeners
for <code class="literal">CHANGE</code> and <code class=
"literal">VALUE_COMMIT</code> events, and when any of these events
is dispatched, the <code class="literal">dataChangeHandler()</code>
pushes provided value from the data attribute of the UI control use
in the form item into the <code class=
"literal">data.dataField</code> property of the object in the
underlying collection.</p>
<p>The <code class="literal">resource</code> setter allows
application developers to use resources the same way as it was done
with a <code class="literal">DataGrid</code> earlier in this
chapter.</p>
<p>The function <code class="literal">commitReadonly()</code>
ensures that the <code class="literal">readOnly</code> property on
the form item can be set only after the item is created.</p>
<p>The function <code class="literal">itemEditorFactory()</code>
supports creation of the form item components from a resource,
based on the specified type property, requests a control to be
created based on a format string. The <code class=
"literal">guessControlFromFormat()</code> is a function that can be
extended based on the application needs, but in the code above it
just uses a <code class="literal">NumericInput</code> component if
the <span class="emphasis"><em>currency</em></span> format was
requested and <code class="literal">DateField</code> if the
<span class="emphasis"><em>date</em></span> format has been
specified. If unknown format was specified, this code assumes that
the application developer needs a mask hence the <code class=
"literal">MaskedInput</code> will be created.</p>
<p>Remember that Flex schedules a call to the function <code class=
"literal">commitProperty()</code> to coordinate modifications to
component properties when a component is created. It's also called
as a result of the application code calling <code class=
"literal">invalidateProperties()</code>. The function <code class=
"literal">commitProperties()</code> checks if the <code class=
"literal">itemEditor</code> is not defined. If it is not, it'll be
created and the event listeners will be added. If the <code class=
"literal">itemEditor</code> exists, the code extracts from it the
UI control used with this form item.</p>
<p>Next, the data form item instantiates the validators specified
by the application developers. This code binds all provided
validators to the data form item.</p>
<a name="I_programlisting3_d1e11269" id=
"I_programlisting3_d1e11269"></a>
<pre><code><span class="bold"><strong>for</strong></span> ( <span class="bold"><strong>var</strong></span> i : int = 0; i &lt; validators.length; i++) {
               <span class="bold"><strong>var</strong></span> validator : Validator = validators[i] <span class="bold"><strong>as</strong></span> Validator;
               validator.property = (_itemEditor <span class="bold"><strong>as</strong></span> DataFormItemEditor).valueName;
               validator.source = control;
               <span class="bold"><strong>if</strong></span> ( validator <span class="bold"><strong>is</strong></span> ValidationRule &amp;&amp; data)
                     validator[<span class="bold"><strong>"data"</strong></span>]= data;
               validator.validate();
          }
</code></pre> 
<p>The next section discusses the benefits of hiding validators
inside the components and offers a sample application that shows
how to use them and the functionality of the <code class=
"literal">ValidationRule</code> class. Meanwhile, <a href=
"#code_fragment_that_uses_da" title=
"Example&nbsp;3.16.&nbsp;Code fragment that uses DataForm and DataFormItem">
Example&nbsp;3.16, &ldquo;Code fragment that uses DataForm and
DataFormItem&rdquo;</a> demonstrates how an application developer
could use the <code class="literal">DataForm</code>, <code class=
"literal">DataFormItem</code>, and resources. Please note that by
default, <code class="literal">DataFormItem</code> renders a
<code class="literal">TextInput</code> component.</p>
<a name="code_fragment_that_uses_da" id=
"code_fragment_that_uses_da"></a>
<p class="title"><b>Example&nbsp;3.16.&nbsp;Code fragment that uses
DataForm and DataFormItem</b></p>

<pre style="height: 600px;"><code>&lt;lib:DataForm dataProvider="employeeDAO"&gt;
    &lt;mx:HBox&gt;
          &lt;mx:Form&gt;
               &lt;lib:DataFormItem dataField="EMP_ID" label="Emp Id:"/&gt;
               &lt;lib:DataFormItem dataField="EMP_FNAME" label="First Name:"/&gt;
               &lt;lib:DataFormItem dataField="STREET" label="Street:"/&gt;
               &lt;lib:DataFormItem dataField="CITY" label="City:"/&gt;
               &lt;lib:DataFormItem dataField="BIRTH_DATE" label="Birth Date:"
                                    formatString="shortDate"/&gt;
               &lt;lib:DataFormItem dataField="BENE_HEALTH_INS" label="Health:"
                    resource="{com.farata.resources.YesNoCheckBoxResource}"/&gt;
               &lt;lib:DataFormItem dataField="STATUS" label="Status:"
                    resource="{com.farata.resources.StatusComboResource}"/&gt;
          &lt;/mx:Form&gt;

          &lt;mx:Form&gt;
               &lt;lib:DataFormItem dataField="MANAGER_ID" label="Manager Id:"/&gt;
               &lt;lib:DataFormItem dataField="EMP_LNAME" label="Last Name:"/&gt;
               &lt;lib:DataFormItem dataField="STATE" label="State:"
                    resource="com.farata.resources.StateComboResource"/&gt;
               &lt;lib:DataFormItem dataField="SALARY" label="Salary:"
                    formatString="currency" textAlign="right"/&gt;
               &lt;lib:DataFormItem dataField="START_DATE" label="Start Date:"
                    formatString="shortDate"/&gt;
               &lt;lib:DataFormItem dataField="BENE_LIFE_INS" label="Life:"
                    resource="{com.farata.resources.YesNoCheckBoxResource}"/&gt;
               &lt;lib:DataFormItem dataField="SEX" label="Sex:"
                    resource="{com.farata.resources.SexComboResource}"/&gt;
          &lt;/mx:Form&gt;

          &lt;mx:Form&gt;
               &lt;lib:DataFormItem dataField="DEPT_ID" label="Department:"
               resource="{com.farata.resources.DepartmentComboResource}"/&gt;
               &lt;lib:DataFormItem dataField="SS_NUMBER" label="Ss Number:"
            itemEditor="{com.theriabook.controls.MaskedInput}" formatString="ssn"/&gt;
               &lt;lib:DataFormItem dataField="ZIP_CODE" label="Zip Code:"
                                                    formatString="zip"/&gt;
               &lt;lib:DataFormItem dataField="PHONE" label="Phone Number:"
           itemEditor="{com.theriabook.controls.MaskedInput}" formatString="phone"&gt;

          &lt;lib:validators&gt;
               &lt;mx:Array&gt;
                     &lt;mx:PhoneNumberValidator  wrongLengthError="keep typing"/&gt;
               &lt;/mx:Array&gt;
          &lt;/lib:validators&gt;
         &lt;/lib:DataFormItem&gt;
          &lt;lib:DataFormItem dataField="TERMINATION_DATE"
                   label="Termination Date:" formatString="shortDate"/&gt;
          &lt;lib:DataFormItem dataField="BENE_DAY_CARE" label="Day Care:"
                  resource="{com.farata.resources.YesNoCheckBoxResource}"/&gt;
          &lt;/mx:Form&gt;
    &lt;/mx:HBox&gt;
&lt;/lib:DataForm&gt;
</code></pre> 


<br class="example-break" />
<p>This code is an extract from the Caf&eacute; Townsend (Clear
Data Builder's version) from Chapter&nbsp;1,
<i>Comparing Selected Flex Frameworks</i>. Run the application
<span class=
"emphasis"><em>Employee_getEmployees_GridFormTest.mxml</em></span>,
double-click on a grid row and you'll see the <code class=
"literal">DataForm</code> in action. In the next section of this
chapter you'll see other working examples of the <code class=
"literal">DataForm</code> and <code class="literal">DataGrid</code>
with validators.</p>

<p><em>The final section of this chapter, part 3, will be published next week.</em></p>]]>
      
    </content>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.36126-comment:2067039</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.36126" type="text/html" href="http://www.insideria.com/2009/05/building-an-enterprise-framewo.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/building-an-enterprise-framewo.html#comment-2067039" />
    <title>Comment from Derby on 2009-06-24</title>
    <author>
        <name>Derby</name>
        <uri>http://www.derby.ac.uk</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.derby.ac.uk">
        <![CDATA[<p>This may surprise you to know that the Pacific region has its fair share of web talent. Having just been surrounded by most of them for the past couple of days I can attest to the fact This year was my first WebDU, and I'm still learning <a href="http://www.derby.ac.uk/ways-to-study">Courses from home</a> <br />
</p>]]>
    </content>
    <published>2009-06-24T09:16:39Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.36126-comment:2069864</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.36126" type="text/html" href="http://www.insideria.com/2009/05/building-an-enterprise-framewo.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/building-an-enterprise-framewo.html#comment-2069864" />
    <title>Comment from Turner on 2009-08-06</title>
    <author>
        <name>Turner</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>The best way of course would be to build test them through the learning  <a href="http://www.ebooknetworking.com">process </a></p>]]>
    </content>
    <published>2009-08-06T09:01:03Z</published>
  </entry>

</feed
