Expanding root of tree in flex

This post is moved to http://srinichekuri.com/2014/02/21/expanding-root-of-tree-in-flex/

**********************************************************************

If you ever want to expand a tree (<mx:Tree>) immediately after setting dataprovider then follow this procedure. The challenge here is tree will not be ready to expand as it takes sometime for it to set data and render.

One common suggestion found on web is to use callLater() to call a function that has code to expand tree. This didn’t work for me (possibly because my code ran into same issue that I highlighted above). But following below method should definetly work as validateNow() method will make sure that all properties are set and will get the tree ready before expanding.

myTree.validateNow();
myTree.expandChildrenOf(_xml,true);

Embedding ttf file using CSS in flex 4 and flex 4.5

This post has been moved to http://srinichekuri.com/2011/06/22/embedding-ttf-file-using-css-in-flex4-and-flex4-5/

**********************************************************************

Earlier in flex3 and flex3.5 embedding fonts using  ttf files could be done straight from CSS files, but this was not working for me when I moved to flex 4.  I found a solution in livedocs.

Embedding TTF file in CSS for flex 3 and flex 3.5
/* CSS file */
@font-face
{
     font-family: myFont;
     src: url(&quot;/fonts/myFont.ttf&quot;);
}

.myStyle
{
    font-family: myFont;
}
Embedding TTF file in CSS for flex 4 and flex 4.5
Step-1:


       [Embed(source='/fonts/myFont.ttf',fontName='myFont',mimeType='application/x-font',embedAsCFF='true')]
       private var font1:Class; //This is only used to compile the code

Step-2:

/* CSS file */
.myStyle
{
    font-family: myFont;
}

3 state checkbox for headerrenderer in datagrid

This post has been moved to http://srinichekuri.com/2011/05/20/3-state-checkbox-for-headerrenderer-in-datagrid/

**********************************************************************

Today I made by first contribution to Adobe Cook by posting about this topic. The idea on this topic started by showing my earlier post on gmail header to my colleague who also happens to be the owner of post in adobe cookbook that talks about 3State checkbox for TreeRenderer. He pointed out that the checkbox in the header can be threeState. Well thats a common problem but suprisingly this was not addressed in the online opensource community for Datagrid. I saw an opportunity and coded it.

Note:
There is a bug in my colleague’s post that it doesn’t take care of the initial state, I have taken care of that bug in my code.My code itself is inspired by my colleagues post.

The checkbox in headerRenderer will have three states:

  • All the rows in the datagrid are selected (‘select’ State).
  • None of the rows in the datagrid are selected(‘unselected’ State)
  • One or more rows (but not all) are selected(‘undecided’ State).

ScreenShots:
Change of state from ‘unselect’ state to ‘select’ state:

Change of state from ‘select’ state to ‘undecided’ state:

Code:

Here is the code for Main.mxml:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;s:Application xmlns:fx=&quot;http://ns.adobe.com/mxml/2009&quot;
				xmlns:s=&quot;library://ns.adobe.com/flex/spark&quot;
				xmlns:mx=&quot;library://ns.adobe.com/flex/mx&quot;
				creationComplete=&quot;creationCompleteHandler(event)&quot;&gt;

	&lt;fx:Script&gt;
		&lt;![CDATA[
			import mx.collections.ArrayCollection;
			import mx.controls.Alert;
			import mx.events.FlexEvent;

			private var _dataProvider:ArrayCollection;
			[Bindable]
			public function set dataProvider(value:Object):void{
				_dataProvider=value as ArrayCollection
			}
			public function get dataProvider():Object{
				return _dataProvider;
			}

			protected function creationCompleteHandler(event:FlexEvent):void
			{
				dataProvider = new ArrayCollection([
					{checked:true, name:'Jim Smith'},
					{checked:false, name:'Yancy Williams'}]);
			}

		]]&gt;
	&lt;/fx:Script&gt;

	&lt;mx:DataGrid id=&quot;myDataGrid&quot; left=&quot;10&quot; top=&quot;10&quot; dataProvider=&quot;@{dataProvider}&quot;&gt;
		&lt;mx:columns&gt;
			&lt;mx:DataGridColumn textAlign=&quot;center&quot; dataField=&quot;checked&quot;
									   width=&quot;90&quot;
									   rendererIsEditor=&quot;true&quot;
									   sortable=&quot;false&quot;
									   itemRenderer=&quot;renderer.CheckboxItemRenderer&quot;
									   headerRenderer=&quot;renderer.ThreeStateCheckBoxHeaderRenderer&quot;
									   /&gt;
			&lt;mx:DataGridColumn headerText=&quot;Name&quot; dataField=&quot;name&quot; width=&quot;110&quot;/&gt;
		&lt;/mx:columns&gt;
	&lt;/mx:DataGrid&gt;

&lt;/s:Application&gt;

Code for headerRenderer

package renderer
{
	import flash.events.MouseEvent;

	import mx.collections.ArrayCollection;
	import mx.controls.DataGrid;
	import mx.controls.Image;
	import mx.controls.dataGridClasses.DataGridListData;
	import mx.controls.dataGridClasses.MXDataGridItemRenderer;

	import spark.components.CheckBox;

	/**
	 * HeaderRender with a Three State Checkbox.
	 * &lt;p&gt;Functionality:&lt;br&gt;
	 * 	  &lt;li&gt;Selecting the checkbox will select all the rows in the datagrid&lt;/li&gt;
	 * 	  &lt;li&gt;Unselecting the checkbox will unselect all the rows in the datagrid&lt;/li&gt;
	 *
	 * &lt;p&gt;The checkbox can be three states at any point:&lt;br&gt;
	 *    &lt;li&gt;select: This would mean that all the rows are selected&lt;/li&gt;
	 * 	  &lt;li&gt;unselect: This would mean that none of the rows are selected&lt;/li&gt;
	 *    &lt;li&gt;undecided: This would mean that one or more (but not all) of the rows are selected&lt;/li&gt;
	 *
	 * @author Srinivas Chekuri
	 *
	 */
	public class ThreeStateCheckBoxHeaderRenderer extends MXDataGridItemRenderer
	{
		protected var myCheckBox:CheckBox;
		protected var myImage:Image;
		private var imageWidth:Number 	= 9.5;
		private var imageHeight:Number 	= 9.5;
		private var inner:String 	= &quot;assets/inner.png&quot;;

		private const SELECT_STATE:String=&quot;select&quot;;
		private const UNSELECT_STATE:String=&quot;unselect&quot;;
		private const UNDECIDED_STATE:String=&quot;undecided&quot;;

		private var STATE:String = UNSELECT_STATE;

		/**
		 * Constuctor
		 *
		 */
		public function ThreeStateCheckBoxHeaderRenderer()
		{
			super();
		}

		/**
		 * overides the function &lt;code&gt;createChildren&lt;/code&gt; in the component lifecyle. This instantiates
		 * &lt;code&gt;myCheckBox&lt;/code&gt; and &lt;code&gt;myImage&lt;/code&gt;.
		 *
		 */
		override protected function createChildren():void{
			super.createChildren();
			myCheckBox = new CheckBox();
			myCheckBox.setStyle(&quot;horizontalCenter&quot;, &quot;0&quot;);
			myCheckBox.setStyle(&quot;verticalCenter&quot;, &quot;0&quot;);
			myCheckBox.addEventListener( MouseEvent.CLICK, checkBoxClickHandler );
			addElement(myCheckBox);
			myImage = new Image();
			myImage.source = inner;
			myImage.addEventListener( MouseEvent.CLICK, imageClickHandler );
			myImage.visible=false;
			addElement(myImage);
		}

		/**
		 * overides the function &lt;code&gt;updateDisplayList&lt;/code&gt; in the component lifecyle. This sets the
		 * display settings of &lt;code&gt;myCheckBox&lt;/code&gt; and &lt;code&gt;myImage&lt;/code&gt;. This also updates the state
		 * according to the selections made in the datagrid.
		 *
		 * @param unscaledWidth
		 * @param unscaledHeight
		 *
		 */
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
			super.updateDisplayList(unscaledWidth,unscaledHeight);

			myImage.x=myCheckBox.x+1.5;
			myImage.y=myCheckBox.y+5.5;

			myImage.width=imageWidth;
			myImage.height=imageHeight;

			if(areAllSelected()){
				STATE=SELECT_STATE;
			}else if(isAnyColumnSelected()){
				STATE=UNDECIDED_STATE;
			}else if(!isAnyColumnSelected()){
				STATE=UNSELECT_STATE;
			}
			checkState();
		}

		/**
		 * Makes adjustments to the &lt;code&gt;visible&lt;/code&gt; property of &lt;code&gt;myImage&lt;/code&gt; and
		 * &lt;code&gt;selected&lt;/code&gt; of &lt;code&gt;myCheckBox&lt;/code&gt; according to the state.
		 *
		 * @private
		 *
		 */
		private function checkState():void{
			if(STATE==SELECT_STATE){
				myImage.visible=false;
				myCheckBox.selected=true;
			}else if(STATE==UNSELECT_STATE){
				myImage.visible=false;
				myCheckBox.selected=false;
			}else{
				myImage.visible=true;
				myCheckBox.selected=false;
			}
		}

		/**
		 * Handler method for &lt;code&gt;MouseEvent.CLICK&lt;/code&gt; event on &lt;code&gt;myImage&lt;/code&gt;.
		 *
		 * @param event
		 *
		 */
		protected function imageClickHandler(event:MouseEvent):void{
			STATE=SELECT_STATE;
			checkState();
			selectAll();
		}

		/**
		 * Handler method for &lt;code&gt;MouseEvent.CLICK&lt;/code&gt; event on &lt;code&gt;myCheckBox&lt;/code&gt;.
		 *
		 * @param event
		 *
		 */
		protected function checkBoxClickHandler(event:MouseEvent):void{
			selectAll();
		}

		/**
		 * Selects all the rows in the datagrid.
		 *
		 */
		private function selectAll():void{
			var ac:ArrayCollection = DataGrid(DataGridListData(listData).owner).dataProvider as ArrayCollection;
			for each (var o:Object in ac){
				o.checked=myCheckBox.selected;
			}
			DataGrid(DataGridListData(listData).owner).dataProvider = ac;
		}

		/**
		 * Checks if all the rows are selected in the datagrid.
		 *
		 * @return Boolean: returns &lt;code&gt;true&lt;/code&gt; if all rows are selected else returns
		 * &lt;code&gt;false&lt;/code&gt;.
		 *
		 */
		private function areAllSelected():Boolean{
			var ac:ArrayCollection = DataGrid(DataGridListData(listData).owner).dataProvider as ArrayCollection;
			var b:Boolean=true;
			for each (var o:Object in ac){
				if(!o.checked){
					b=false;
					break;
				}
			}
			return b;
		}

		/**
		 * Checks to see if any one of the rows are selected.
		 *
		 * @return Boolean: return &lt;code&gt;true&lt;/code&gt; if any one the rows are selected.
		 *
		 */
		private function isAnyColumnSelected():Boolean{
			var ac:ArrayCollection = DataGrid(DataGridListData(listData).owner).dataProvider as ArrayCollection;
			var b:Boolean=false;
			for each (var o:Object in ac){
				if(o.checked){
					b=true;
					break;
				}
			}
			return b;
		}
	}
}

Code for itemRenderer:

&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;

		&lt;![CDATA[
			import mx.collections.ArrayCollection;
			import mx.controls.DataGrid;
			import mx.controls.dataGridClasses.DataGridListData;
			import mx.events.FlexEvent;

			/**
			 * Handler function for &lt;code&gt;MouseEvent.CLICK&lt;/code&gt; on checkbox.
			 *
			 * @param event MouseEvent
			 *
			 */
			public function clickHandler(event:MouseEvent):void{
				var o:Object = DataGrid(DataGridListData(listData).owner).selectedItem;
				o.checked=cb.selected;
				ArrayCollection(DataGrid(DataGridListData(listData).owner).dataProvider).setItemAt(o,DataGrid(DataGridListData(listData).owner).selectedIndex);
			}

			/**
			 * Overides &lt;code&gt;data&lt;/code&gt; parameter to set the &lt;code&gt;selected&lt;/code&gt; parameter of the
			 * checkbox.
			 *
			 * @param value Object
			 */
			override public function set data(value:Object):void{
				if(value!=null){
					super.data=value;
					cb.selected=value.checked;
				}
			}
		]]&gt;

You can download the code from my post in Adobe cook book.

Google Mail like header component for Datagrid/AdvancedDatagrid in flex4

This post has been moved to http://srinichekuri.com/2011/04/23/google-mail-like-header-component-for-datagridadvanceddatagrid-in-flex4/

********************************************************************

I have tried to look around on web for a opensource component that simulates google mail(gmail) header like behavior in flex but couldn’t find one. As any other developer I have built my own component and am posting for the online community to make use of it.

You can have a look at the component here:

View Component

You can download the source code for this component here:

Download source code

As you can see I have customized the options that appears in the menu when you click on the arrow of the header. I will explain the behavior of the component before I take a deep drive into the code.

  • You can click on the arrow to select any one of the options given. I have put in 3 options:
    • All: Selects all the columns in the datagrid
    • None: Selects none of the rows and deselects rows if there are any already selected
    • Top 5: Select top 5 columns in the grid
  • Click on the checkbox on the header either select/deselects all the rows.

Here are few screen shots:

Click on the ‘Top5’ Option in the Header:

Component when top5 option is selected

 

Click on the CheckBox in the Header:
Component when the checkbox is clicked

Explanation of the code:
There are two main files that contribute as Datagrid’s header renderer:
DropDownButton:

package com.customization.controls
{
import com.customization.event.DropDownEvent;
import com.customization.skin.DropDownButtonSkin;

import flash.events.MouseEvent;

import mx.controls.Alert;
import mx.controls.Menu;
import mx.core.FlexGlobals;
import mx.core.mx_internal;
import mx.events.MenuEvent;
import mx.styles.CSSStyleDeclaration;
import mx.styles.IStyleManager2;
import mx.styles.StyleManager;

import spark.components.Button;

/**
 * Event dispatched when an option is selected from the dropdown menu.
 *
 * @eventType com.customization.event.DropDownEvent.OPTION_SELECTED
 */
[Event(name="optionSelected", type="com.customization.event.DropDownEvent")]
/**
 * DropDownButton extends <code>Button</code> component. When the button is clicked menu is
 * shown with options that can be selected.
 *
 * @author Srinivas Chekuri
 * @see DropDownSelector
 */
public class DropDownButton extends Button
{
/**
 * XML that defines the menu that should be displayed when clicked on the button.
 *
 * @default <xml></xml>
 */
public var myMenuData:XML=<xml></xml>;
private var menu:Menu;

public function DropDownButton()
{
super();
}

/**
 * overrides the initialize method of <code>mx.controls.Button</code>. EventListener are added to
 * <code>MouseEvent.CLICK</code> on this component and <code>MenuEvent.ITEM_CLICK</code> on Menu.
 * <code>skinClass</code> is set to <code>com.customization.skin.DropDownButtonSkin</code>.
 *
 */
override public function initialize():void {
super.initialize();
this.addEventListener(MouseEvent.CLICK,buttonMouseClickHandler);
this.setStyle("skinClass",com.customization.skin.DropDownButtonSkin);
menu = Menu.createMenu(null, myMenuData, false);
menu.labelField="@label";
menu.addEventListener(MenuEvent.ITEM_CLICK,menuClickHandler);
}

/**
 * Handler methos for mouse click on the button. This shows the menu.
 *
 * @param event MouseEvent
 *
 */
private function buttonMouseClickHandler(event:MouseEvent):void{
menu.show(this.x,20);
}

/**
 * Handler method that will be called when option is selected in the menu by a mouse click.
 *
 * @param event MenuEvent
 *
 */
private function menuClickHandler(event:MenuEvent):void{
var dropDownButtonEvent:DropDownEvent = new DropDownEvent(DropDownEvent.OPTION_SELECTED);
dropDownButtonEvent.selectedOption=event.item.@label;
dispatchEvent(dropDownButtonEvent);
}
}
}

DropDownSelector:

package com.customization.controls
{
import com.customization.event.DropDownEvent;

import flash.events.MouseEvent;

import mx.containers.HBox;
import mx.controls.Alert;

import spark.components.CheckBox;
import spark.components.HGroup;

/**
 * Event that is thrown when the checkbox is checked or unchecked.
 *
 * @eventType com.customization.event.DropDownEvent.CHECKBOX_STATUS_CHANGE
 */
[Event(name="checkBoxStatusChange", type="com.customization.event.DropDownEvent")]
/**
 * DropDownSelector is a class that hosts a google mail like header component that will allow us
 * to select the options from the drop down menu.
 *
 * @author Srinivas Chekuri
 * @see DropDownButton
 */
public class DropDownSelector extends HBox
{
private var checkBox:CheckBox;
private var button:DropDownButton;
private var myMenuData:XML=<XML>
<menuitem label="All"/>
<menuitem label="None"/>
<menuitem label="Top 5"/>
</XML>;
/**
 * Constructor.
 *
 */
public function DropDownSelector()
{
super();
intializeView();
}

/**
 * Method that initialize the views by instantiating the checkbox and the DropDownButton component.
 * This also adds event listeners to clicks on both these components.
 *
 * @private
 */
private function intializeView():void{
this.setStyle("horizontalGap",0);
this.setStyle("verticalGap",0);
this.setStyle("horizontalAlign","center");
this.setStyle("verticalAlign","center");
//Initializing CheckBox
checkBox = new CheckBox();
checkBox.horizontalCenter=0;
checkBox.verticalCenter=0;
checkBox.addEventListener(MouseEvent.CLICK,checkboxMouseClickHandler);
checkBox.horizontalCenter=0;
checkBox.verticalCenter=0;

//Initializing DropDownButton
button = new DropDownButton();
button.myMenuData=myMenuData;
button.width=15;
button.horizontalCenter=0
button.verticalCenter=0;
button.addEventListener(DropDownEvent.OPTION_SELECTED,optionSelectHandler);

this.addChild(checkBox);
this.addChild(button);
}

/**
 * Handler method when checkbox is clicked. When ever this method is called
 * <code>DropDownEvent.CHECKBOX_STATUS_CHANGE</code>id dispatched.
 *
 * @param e MouseEvent dispatched.
 * @eventType com.customization.event.DropDownEvent.CHECKBOX_STATUS_CHANGE
 */
protected function checkboxMouseClickHandler(e:MouseEvent):void{
var event:DropDownEvent = new DropDownEvent(DropDownEvent.CHECKBOX_STATUS_CHANGE);
event.checkBoxSelectStatus=e.target.selected;
dispatchEvent(event);
}

/**
 * Handler method when a option gets selected from dropdown menu.
 *
 * @param event DropDownEvent dispatched.
 *
 */
protected function optionSelectHandler(event:DropDownEvent):void{
if(event.selectedOption!=null){
checkBox.selected=true;
}
}
}
}

Apart from this you might also want to look at DropDownButtonSkin.mxml for skinning and Customization.mxml on how the events were handeled.