Hello. I have a new blog.

I've moved this blog to the following URL Kerkness.ca. Thank you for visiting, please update your bookmarks.

Showing posts with label flex. Show all posts
Showing posts with label flex. Show all posts

Thursday, November 6, 2008

Creating an ItemRenderer in ActionScript

I'm posting this for my benefit as much as anyone else. Here is a very basic ItemRenderer done in ActionScript. Something you might come across when building Flex/Air applications is errand problems with ItemRenderer's not performing as expected, sucking up lots of memory, or throwing errors. Many times these problems can be solved by building your renderer in ActionScript. Here is the source for a basic item renderer which can be scaled up as needed.

package my.renderer
{
 import my.model.DataModel;
 
 import mx.controls.Label;
 import mx.controls.listClasses.IListItemRenderer;
 import mx.controls.listClasses.ListBase;
 import mx.core.UIComponent;
 
 public class ArtListRenderer extends UIComponent implements IListItemRenderer
 {
  public function ArtListRenderer()
  {
   super();
  }
  
  
     [Bindable] public var myData:DataModel = new DataModel();
  
     // Internal variable for the property value.
     private var _data:Object;
     
     // Make the data property bindable.
     [Bindable("dataChange")]
     
     // Define the getter method.
     public function get data():Object {
         return _data;
     }
     
     // Define the setter method, and dispatch an event when the property
     // changes to support data binding.
     public function set data(value:Object):void {
         _data = value;
         
         myData = new DataModel();
         myData.firstname = value.firstname;
         myData.lastname = value.lastname;
                 
         invalidateProperties();
         dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
     }
     
     private var hBox:HBox;
     private var firstnameLabel:Label;
     private var lastnameLabel:Label;
     
     override protected function createChildren():void
     {
      super.createChildren();
      
      hBox = new HBox();
      
      firstnameLabel = new Label();
      lastnameLabel = new Label();
      hBox.addChild( firstnameLabel );
      hBox.addChild( lastnameLabel );
      
     }  
     
     override protected function commitProperties():void
     {
      super.commitProperties();
      
      hBox.horizontalScrollPolicy = 'off';
      hBox.verticalScrollPolicy = 'off';
      
      hBox.percentWidth = 100;
      
      firstnameLabel.text = myData.firstname;
      lastnameLabel.text = myData.lastname;
     }
     
     override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
     {
      super.updateDisplayList(unscaledWidth,unscaledHeight);
      hBox.move(0,0);
      hBox.setActualSize( (unscaledWidth-4), unscaledHeight);
     }
 }
}

Friday, October 3, 2008

Force creation of complete ViewStack with creationPolicy when building a form across multiple views : Flex Tip

Here's a tip which might be useful for some people.  Sometimes when building a Flex/Adobe Air interface you may want to have form elements which are built across multiple views of a ViewStack, or TabNavigator.  For example I have a contact form which has some rarely used fields contained in a secondary Tab in my form.

Problem with this approach is that the default value of a Container's creationPolicy is 'auto'.  This means child components are only created when they are needed.  If your user never looks at the extra tabs/view stack layers then these form elements are not available if you need to get values or set values for them.

The Solution is to simple set the creationPolicy for your ViewStack or TabNavigator to 'all'.  This will ensure that all child elements are created up front and are available when needed regardless if the user looks at them or not.

Thursday, October 2, 2008

Flex Tip : Use ObjectUtil for Alpha and Numeric sorting on a DataGrid

If you haven't taken the time to look at the features of Flex's ObjectUtil you should. Inside are a few handy methods which I see getting over looked.

Two of those methods are ObjectUtil.stringCompare and ObjectUtil.numericCompare. These methods make it simple to provide intelegent sorting on DataGrid columns.

Let's say you have a DataGrid that has one column full of ID# and another column full of people's names including both first and last names. Chances are the default sorting abilities of the DataGrid will not properly sort either column. The ID# would be sorted 1,10,11,12... instead of 1,2,3,4,5... and the column of names would sort by the first name and not the last name.

Lucky the DataGridColumn allows you to set a custom sort function via the property sortCompareFunction. For example look at these two DataGridColumns.

<mx:DataGridColumn headerText="ID#" dataField="contactid" sortCompareFunction="sortContactId"/>
<mx:DataGridColumn headerText="Name" dataField="full_name" sortCompareFunction="sortLastName">
 <mx:itemRenderer>
  <mx:Component>
    <mx:Label paddingLeft="5" text="{data.firstname} {data.lastname}" />
  </mx:Component>
 </mx:itemRenderer>
</mx:DataGridGolumn>

The first column is for the ID# of a contact, the second column uses an itemRenderer and displays both the firstname and lastname for the contact. Each column defines it's own sortCompareFunction. Both functions make use of methods from mx.utils.ObjectUtil.

private function sortLastName(obj1:Object,obj2:Object):int
{
   var value1:String = (obj1.lastname == '' || obj1.lastname == null) ? null : new String(obj1.lastname);
   var value2:String = (obj2.lastname == '' || obj2.lastname == null) ? null : new String(obj2.lastname);
   return ObjectUtil.stringCompare( value1, value2, true );
}
private function sortContactId(obj1:Object,obj2:Object):int
{
   var value1:Number = (obj1.contactid == '' || obj1.contactid == null) ? null : new Number(obj1.contactid);
   var value2:Number = (obj2.contactid == '' || obj2.contactid == null) ? null : new Number(obj2.contactid);
   return ObjectUtil.numericCompare( value1, value2 );
}

These functions are pretty straight forward.  sortLastName function uses stringCompare method to compare the lastname from two objects. The flag 'true' is set to make sure that the comparison is case insensitive. The sortContactId function uses the numericCompare method to compare the contactid from two objects.

Wednesday, October 1, 2008

Flex Component : ButtonPanel puts a button in your panel header

It's always a joy when you need something and after writing a few lines of code, you have it. Such is the beauty of nice extendable components and the Flex architecture.

Today I needed a panel which had a button in the top right corner of the header. Where the 'status' text is normally is. I wanted to put a 'save' button there. One problem, the mx.containers.Panel component does not have a button in the header.

Solution. Make a new component which extends all the functions of the Panel and stick a button in the top corner where I want.

Click here to see a demo

Click here to view the source

My new ButtonPanel component extends Panel and adds 2 new properties and 1 event.

Properties

buttonLabel : String - Defines the label for the button in the top corner
buttonPadding : Number - Defines how much padding to provide in the header

Event

buttonClick : Event - Dispatched when the button is clicked

Friday, August 29, 2008

Flex : DataGrid ItemRenderer and DoubleClick Oh My !!

I love it when you come across those little 'gotchas' when programming. Today I found one and it took a while to figure out a solution/hack so I thought I would post my findings and save someone else a little time.

Scenario: You have a DataGrid which uses an ItemRenderer to display the contents of a cell and you need this DataGrid to respond to DoubleClick events.

Problem: The DoubleClick does not fire when the clicking occures in the white space of the item renderer.

Solution: Enable DoubleClick in the itemRenderer as well and send the event to a dummy event handler.

Here's an example to clarify. First a MXML component containing the DataGrid.

<mx:Script>
<![CDATA[
import mx.controls.Alert;
private function dblClickHandler(event:ListEvent):void
{
Alert.show("Double your fun");
}
]]></mx:Script>
<mx:DataGrid id="myGrid" width="100%" dataProvider="{myArrayCollection}"
doubleClickEnabled="true" itemDoubleClick="dblClickHandler(event)">
<mx:columns>
<mx:DataGridColumn headerText="Col1" itemRenderer="claire.renderer.myCol" />
</mx:columns>
</mx:DataGrid>

Here is the itemRenderer claire.renderer.myCol. Basically we enable double click and for the doubleClick event and we send the event to a dummy handler

<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" doubleClickEnabled="true"
doubleClick="dummyClickHandler(event)">
<mx:Script>
<![CDATA[
private function dummyClickHandler(event:Event):void
{
// do nothing
}
]]>
</mx:Script>
<mx:Label text="{data.artistName}" fontWeight="bold"/>
<mx:Label text="{data.artworkMedium}" fontStyle="italic"/>
<mx:Label text="{data.artworkSize}"/>
</mx:VBox>

Thursday, July 31, 2008

Updated Flex Qwerty Component

I've made some updates and improvements to my Flex Qwerty Keyboard Component.

This version of the component is a little more tailored for a touch screen kiosk and is modled a little after the soft-touch keyboard you see on Apples' iPhone. The main new features are shortcut buttons for typing '.com' and '.ca' (cause I'm Canadian) as well as a 'Tab' button for tabbing through form fields.

You can view a demo of the updated component here.

You can view the source code for the updated component here.

How to Customize this Component

I've had a few comments and questions about how to customize this component. It should be fairly straight forward to do if all you want to do is add or modify how a button works. Here are instructions on how to add an 'Enter' or 'Return' button to the keyboard.

  1. First step is to physically add the button to the keyboard. This can be done by adding a new object to one of the keyRow arrays in the qwerty.mxml file. Adding the following object to the end of the keyRowC array will add the button to the end of row 3 of the keyboard.
    {label:'Return',w:100}
    The property 'w' specifies that the button should be 100 pixels wide. Alternatively you could set the property 'flex' to 'true' which would make the button take up as much available space as is available.

  2. Next you need to instruct the component on how to handle the click event for this new button. You do this by adding a condition to the switch statement in the function handleKeyClick(). Add the following condition for the new Return button.
    case 'Return': this.inputControl.text += "\n";break;
  3. Finally we need to modify the function which handles toggling between Upper and Lower case on the keyboard. We don't want our new button to be affected by this toggling so we will adjust this function to bypass our new button.

    In the function toggleUpperLower() edit the following line from this...
    if ( kidLabel == 'Tab' || kidLabel == 'Delete' ) continue;
    to this...
    if ( kidLabel == 'Tab' || kidLabel == 'Delete' || kidLabel == 'Return' ) continue;
There you go, you should have a functional return button. If you have any problems with this example please let me know in the comments.

Thursday, June 26, 2008

Flex Component : Yet Another Flex File Upload Component

There are several Flex upload components floating around and I gave most of them a good look over but I was not able to find one which suited my needs so I decided to make my own. Here it is for you to enjoy.

Click here to view a demo
(demo lets you upload up to 3 files at a time with a max size of 4 megs each)

Click here to view the source

The usage of the component is pretty straight forward. You can set some properties to define what types of files can be uploaded and you direct the 'upload' towards a server side script. In my demo I send the files to a basic PHP script ( which I've included below ). The script handles one file at a time and is expected to report back either the string 'successful' or an error message which is displayed.

Properties

The following public properties can be set to customize the use of this component

  • uploadButtonLabel : String = 'Upload'
    This is the label used for the 'upload' button.

  • selectButtonLabel : String = 'Select File(s)'
    This is the label used for the 'select' button.

  • removeButtonLabel : String = 'Remove Selected File'
    This is the label used for the 'remove' button.

  • maxFileCount : Number = 3
    This sets the number of files a user is allowed to upload

  • maxFileSize : Number = 1
    This sets the maximum file size (in megs) for each individual file. Default is 1 meg.

  • requestUrl : String = ''
    This is the URL for your PHP/ASP/ColdFusion/Other script which you will send the uploaded files to. THIS PROPERTY MUST BE SET !

  • allowOnlyImages : Boolean = false
    If set to 'true' the user will only be able to select image files

  • allowOnlyText : Boolean = false
    If set to 'true' the user will only be able to select text files.

  • allowAllFiles : Boolean = true
    If set to 'true' the user can upload images or text files.

  • barColor : String
    Allows you to style the progress bar
Events

The component has one event 'uploadComplete' which is triggered if all files are uploaded successfully.

The PHP Handler

Following is the source for the simple PHP script which I am using in the demo. In this script I am just confirming that the file was uploaded successfully and then I am deleting it. Since this is a public demo I don't want people filling up my server with unwanted images. In your script you would most likely copy the FILE to a more permanent location and possibly do a little more validation. The script needs to echo the string 'success' or echo an error message.
$hasError = false;
foreach( $_FILES as $i=>$file ){
if ( $file['error'] ){
$hasError = true;
}
/**
* Because this is a public example. I am just going to immediately delete
* the file which was uploaded. In a regular application you would copy the file
* from it's temporary location to it's permament location.
*/
unlink( $file['tmp_name'] );
}

if ( ! $hasError ){
echo('success');
} else {
echo('Stick custom error message here');
}

Wednesday, June 4, 2008

Something I need to remember about ItemRenderers and the TileList control

From a high level perspective, scrolling is moving data through fixed itemRenderers, not by actually moving renderers off the visible area of
the screen.
I found this little bit of information hidden in this thread. After trying to extensively use my PageList component in a large application and with a dataProvider that had the potential of providing hundreds of items needing rendering I was noticing a very bad side effect. My application would continue to create a new instance of the itemRenderer for every item in the dataProvider and if the dataProvider was emptied ( ie: arrayCollection.removeAll() ) the itemRenderers would remain.

Back to the drawing board on that one. I hope to post a new PageList component soon as my application is not usable in it's current state.

Tuesday, May 20, 2008

Multiple AutoComplete Input Controls in a single Flex Form

A very nice component which is available from Adobe is their AutoComplete ComboBox. The AutoComplete Combo box looks like a regular TextInput component but will provide suggestions to the user as they type. This is very handy when you want to let users select from a long list of options ( such as a list of Countries ).

Jen Krause has posted a modified version of the component which allows the user to press ENTER, TAB or click their mouse button to select the first selected item. This is a very nice modification.

A problem I ran into however was using multiple AutoComplete components in the same Flex form. If you try and put more than one AutoComplete component in the form, the first component looses the label of the selected item when you begin using the second component. I wasn't able to determine the cause of this problem but I was able to provide a simple work around.

If you've run into a same problem, you can fix it by making the following change to the class' focusOutHandler method.

// Change this method ...
override protected function focusOutHandler(event:FocusEvent):void
{
super.focusOutHandler(event)
if(keepLocalHistory && dataProvider.length==0)
addToLocalHistory();
}

// To this ....
override protected function focusOutHandler(event:FocusEvent):void
{
super.focusOutHandler(event)
if(keepLocalHistory && dataProvider.length==0)
addToLocalHistory();
_typedText = textInput.text; // replace typedText with textInput.text
}

I'm not sure if there are any ramifications to this fix but I haven't found any additional problems in my own application.

UPDATE
Turns out there are numberous implications when using multiple AutoComplete Input controls in the same form specifically when you want to try and set the value of the controls with actionscript. If you only need one AutoComplete input control then this component works really well and is very user friendly. However if you need multiple controls you may want to re-consider your form design choices.

Thursday, April 17, 2008

warning: unable to bind to property 'XX' on class 'Object' (class is not an IEventDispatcher)

When working with data pulled in from an HTTPService in Flex you may find that at run time your application spits out a bunch of warnings that it is unable to bind to a property.

If you want to prevent these warnings from occuring you should process your the data for your in actionscript instead of MXML.

Change this ...

<mx:Label text="{myresults.dynamiclabel}"/>
To this ... ( calling the function init() with the creationComplete event )
<mx:Script>
[Bindable] private var dynamiclabel:String;
private function init():void
{
this.dynamiclabel = myresults.dynamiclabel;
}
</mx:Script>
<mx:Label text="{this.dynamiclabel}"/>
I know this approach requires a little bit more code and the first approach works, but this way it doesn't result in any warnings. I'll make the assumption that no run-time warnings means more compliant code.

Another approach to solving the problem is by wrapping Arrays in ArrayCollection and Objects in ObjectProxy wrappers. I got the following example from here.
function resultHandler(result:Array)
{
for(var i:String in result)
{result[i] = new ObjectProxy(result[i]);}
targetArrayCollection = new ArrayCollection(result);
}
What about using ItemRenderer(s)?

If you are combining the use of an ItemRenderer and data from an HTTPService in your application you may find that neither of the above solutions fully work. What you really need is a modification of the first solution. Collecting your data in response to the creationComplete event will only collect data when the itemRenderer is first created. The event is not called when dynamically change the dataProvider. An approach to solving this scenario is the create a ChangeWatcher in the ItemRenderer to respond to changes to the data property of said ItemRenderer.

<mx:Script>
import mx.binding.utils.ChangeWatcher;
import mx.events.PropertyChangeEvent;

private var dataWatcher:ChangeWatcher;

[Bindable] private var dynamiclabel:String;

// ** Call this function from creationComplete event **
private function init():void
{
this.dataWatcher = ChangeWatcher.watch( this, 'data', dataChangeHandler );
this.dataChangeHandler();
}

private function dataChangeHandler(event:Event=null):void
{
this.dynamiclabel = data.dynamiclabel;
}
</mx:Script>
<mx:Label text="{this.dynamiclabel}"/>

Wednesday, April 16, 2008

Upgrading to FlexBuilder Linux Alpha 3 on Ubuntu 7.10 after Flexbuilder Alpha 2 expires

This post is probably a month overdue but I've been working on a Mac OSX workstation for the last month ( my Dad has a nice new Mac so while he was on vacation I used his computer ). Anyway, my dad came back so I moved back to my trusty Ubuntu workstation at my own desk. To my surprise the Alpha version of the Adobe Flex Builder Linux had expired. I have licensed copies for Flex Builder for both Windows and Mac but there is no release for Linux yet so I'm left using alpha versions.

The good news is that if your copy of Flex Builder Alpha 2 has expired (which I think everyone's did on March 15th) all you need to do is uninstall Flex Builder Alpha 2 and install Flex Builder Alpha 3. There are some new requirements however which makes this process a little more complicated if you're running Ubuntu. Mainly, Flex Builder Alpha 3 requires Eclipse 3.3 and the version of Eclipse which can be installed from Ubuntu repository is only version 3.2

So here are the steps you need to follow if you want to get Flex Builder Alpha 3 installed on Ubuntu after Flex Builder Alpha 2 has expired. Instead of writing a full howto I'm going to link you to the different blogs/pages which have the instructions you'll need.

  1. (Optional) If you haven't already upgraded to Ubuntu 7.10 now would be a good time. I was running Fiesty Fawn (which is 7.04 I think). View this link to get that done.

  2. Next you need to install Eclipse 3.3 on your system. Follow the instructions at this link but be insure to install 3.3 to a different location than 3.2. After you have 3.3 running you can copy the contents to the eclipse folder to the location where you have 3.2 installed. Mine was located at ~/.eclipse

  3. Before installing Flex Builder Alpha 3 you'll need to uninstall Flex Builder Alpha 2. To do this you need to run the script Uninstall_Adobe_Flex_Builder_Linux. This will be located in the directory Uninstall Adobe_Flex_Builder_Linux which in turn exists in the Flex Builder Linux installation directory. For full details see the Uninstall section of the release notes for alpha 3.

  4. Download Flex Builder Alpha 3

  5. Open your terminal and run the downloaded .bin file. For me I typed the following.
    cd /home/ryan/Desktop
    sh flexbuilder_linux_install_a3_033108.bin
    Follow the onscreen instructions.

  6. When finished you should be able to fire up Alpha 3. You may find that you get an error when opening older project files saying that the file is out of sync. Just right-click on the project and select the 'Refresh' option.

  7. If you need to add a launcher for the Flex Builder Alpha 3 program, the default location of the command to launch the program is
    /home/ryan/Adobe_Flex_Builder_Linux/Adobe_Flex_builder.sh
    Assuming of course that you're user name is 'ryan' like mine is.

Saturday, April 5, 2008

Customizing the Flex ScrollBar with Skins

One of the things I love about Flex is the smooth and clean look/feel of the default components. With just a little CSS the default look and feel can be customized to fit most web site designs. But what do you do when your requirements are very different from what you can accomplish with CSS? With Flex it's possible to build custom skins and give you're application any look and feel you desire.

While the process to complete this isn't overly complex it probably helps if you come from a Flash background and also have some strong design skills.

There are two ways to build skins. 1) Use images and 2) Use actionscript classes. For my example I have combined both approaches to customize the look/feel of the default Flex scrollbar.

Summary of the solution

- Create a PNG image to use as the background for the scrollbar track.
- Create a PNG image to use as the icon for the scrollbar handle.
- Create an ActionScript class to draw a skin for the scrollbar box.
- Create a CSS Style for the scrollbar which references the new skins
- Apply the StyleName to our scrollbar

The CSS Style

.customScroll
{
/* remove the arrow skins by referencing a null class */
upArrowSkin: ClassReference(null);
downArrowSkin: ClassReference(null);

/* Embed an image to use as skin for scroll bar track and scroll bar thumbIcon */
trackSkin: Embed(source="skins/CustomSkinTrack.png");
thumbIcon: Embed(source="skins/CustomSkinIcon.png");

/* Reference action script skin for various states of the scroll bar thumb */
thumbUpSkin: ClassReference('theme.skins.CustomSkinThumb');
thumbOverSkin: ClassReference('theme.skins.CustomSkinThumb');
thumbDownSkin: ClassReference('theme.skins.CustomSkinThumb');
}


Click here to view the demo.
Click here to view the source code.

Monday, March 17, 2008

Flex SuperLabel Component : An Easy How To on Extending Flex Components with Custom Events and Effects

Since I switched from developing XUL/Javascript based RIAs using the Mozilla platform to programming in Flex and Actionscript one of the things I have been most impressed with is how easy it is to extend existing components and customize them to fit my needs perfectly.

Recently (as in 10 minutes ago) I was working on laying out the interface for a new application which displays some dynamically changing content. One part of the interface which was dynamically changing was the page title which I was displaying as a Label component. I thought it would be nice to add a small effect every time the text property for Label changed. Looking at the language reference documentation for the Label component I noticed there was no built in event or effect which could be triggered when the text property is updated.

No problem, I thought. I'll just add that in. So with less than 25 lines of code and in less time than it is taking to type this post I was done.

Here is a summary of the steps I took to create my new SuperLabel Component.

  • Created a new Actionscript Class
  • Added Metatags for the new Event and new Effect
  • Created a function which overrides the text property setter function
  • done.
Here is the source code for the new component.
package claire.com
{
import mx.controls.Label;
import flash.events.Event;

[Event(name="textChange", type="flash.events.Event")]
[Effect(name="textChangeEffect", event="textChange")]

public class SuperLabel extends Label
{
public function SuperLabel()
{
super();
}
public override function set text(value:String):void
{
if ( value != this.text )
{
this.dispatchEvent( new Event('textChange') );
}
super.text = value;
}
}
}
There you go. It really is that easy.

Just to finish off here is how you use the new component in MXML.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:com="claire.com.*">
<mx:WipeRight id="myEffect" duration="750" />
<com:SuperLabel textChangeEffect="{myEffect}"/>
</Application>

Thursday, March 13, 2008

Flex Tip: Positioning components in Adobe Flex with no default gaps, padding or margins

If you're new to Flex and you've been banging your head against a wall trying to get components to position themselves properly then hopefully this tip will help.

By default Flex adds about a 10px margin around most components. For example if you're trying to create a row of buttons that are all butted right up against each other with no space in between the following code won't cut it.

<!-- these buttons will all have about a 10px gap in between them -->
<mx:HBox>
<mx:Button label='Button 1'/>
<mx:Button label='Button 1'/>
<mx:Button label='Button 1'/>
</mx:Hbox>

To make that gap go away you need to add horizontalGap="0" to the HBox tag as in the following example
<!-- these buttons will have no gap in between them -->
<mx:HBox horizontalGap="0">
<mx:Button label='Button 1'/>
<mx:Button label='Button 1'/>
<mx:Button label='Button 1'/>
</mx:Hbox>

So there you go. horizontalGap="0" and like wise verticalGap="0" is what you're looking for if you can't figure out why your components have a default margin.

Wednesday, March 12, 2008

Flex Tip: Adding custom events to Actionscript components

One of the key features of building a Flex application with custom components is being able to define and dispatch custom events. In order to do this you need to add some metadata to your custom component.

If you're creating an actionscript class for your custom component you declare the metadata before defining your class as in the following example.

package claire.libs
{
....
[Event(name="serviceError", type="flash.events.Event")]
public class ClaireService extends HTTPService
{
.....
}
}

You will now be able to add an event listener in MXML with the following.
<mycom:ClaireService id="myService" serviceError="handlerFunction(event)"/>

While the above example works it is important to note that the following example will NOT work. Notice the ";" at the end of the Event metatag. Took me about 2 hours to figure this out so hopefully this post will save someone else some time.
package claire.libs
{
....
[Event(name="serviceError", type="flash.events.Event")];
public class ClaireService extends HTTPService
{
.....
}
}

Friday, March 7, 2008

Control Access to Flex Components with Group Based Permissions

When building a large application which has many different views it's likely that you'll want to grant some users more access than others. You might have some components that all guests are permitted to view and also have other components that only admin users are allowed to use.

A common way to accomplish this is to assign all users to different user groups and then control what user groups are allowed to view certain parts of your application.

The example I show here focuses only on controlling the 'visible' property of a component and therefore only addresses what interface elements the user is allowed to see. I plan to expand on this example in the future to also address the user's ability to access specific sets of data.

Permit and PermitCondition Classes

In order to have a central repository of permissions and information on the current user I created a singlton class called Permit and another class called PermitCondition. Using a singlton ensures that only one instance of the class will be created and can still be easily accessible anywhere in your application.

The Permit class keeps information on the current user and is responsible for creating instances of the PermitCondition class.

Each instance of PermitCondition defines a single permission requirement for a single component by declaring if a specific user group is allowed to view the component or is explicitly blocked from viewing the component. Components can have multiple PermitConditions allowing for more complex permissions.

Summary of Example Application

View the demo : View demo source

In my example application I define permissions for 3 sample components in the main MXML application file. I then use a LogIn component which sets the user's group memberships. Both the main MXML application and the LogIn component use the same singlton instance of the Permit class.

For the purpose of keeping this example simple my LogIn component manually sets users group permissions from a couple of simple functions. In a more complete application you would want your LogIn component to accept a username and password and define user groups after calling an HTTPService and likely querying a database.

Creating and Accessing the Permit Class

Use the following code to get access to the Permit singlton.

import claire.libs.Permit;
private var appPermit:Permit = Permit.getInstance();
Defining Component Permissions

Use the following code to define permissions for individual components
appPermit.applyPermit('adminaccess',Permit.ALLOW,'admin',box3);
appPermit.applyPermit('adminaccess',Permit.BLOCK,'guest',box3);

The applyPermit method accepts 4 properties
applyPermit( permitname:String, condition:String, group:String,component:UIComponent)
  • permitname : A unique identifier for the declared permit.
  • condition: Accepted values are Permit.ALLOW or Permit.BLOCK. Determines if the supplied group name is granted or blocked access to component.
  • group: Name of a user group checked in the condition.
  • component: a UIComponent which the permit is applied against.

Adding User Details to the Permit Class

Use the following code to add user details to the Permit class after successfully validating the user's username and password.
appPermit.loggedIn = true;
appPermit.addGroup('guest') // Adds user to group 'guest'
When a user is added to a group the Permit class will automatically check PermitConditions and update the visible property of components.

Wednesday, March 5, 2008

Sudoku Updated

I've had a chance to add some nice features to my Sudoku game. User's can now save their games and return later to pick up where they left off. I've limited each user to 6 saved games and they must register a username/password first. Email is not required for registration because what would be the point.

This whole Sudoku game has basically been an exercise to learn about Flex development and see what it takes to build a full application. I have to say that I am very impressed with what I've been able to accomplish in a short period of time.

Anyway. If you like Sudoku I would appreciate any comments you might have on my game.

http://www.kerkness.ca/sudoku

Tuesday, March 4, 2008

Searching a complex ArrayCollection in Flex and how I hate the damn IViewCursor

I'll preface this post as I do many by stating that I'm relatively new to Actionscript and Flex so I'm not really sure if the code I present here is a solution or a hack. In either case it works.

While building a 'Save Game' feature for my Sudoku game I was came across a situation where I needed to search an existing ArrayCollection for the ID of a previously saved game. I knew what the ID was but just needed to locate it's index position in the collection. While looking at the Flex documentation I noticed that the ArrayCollection component has a nice method called getItemIndex. However this wasn't going to be any use to me because getItemIndex only finds exact matches of an entire object and I needed to match only a single value. This lead me to look into the use of an IViewCursor.

While creating a cursor to access and manipulate and ArrayCollection seems like an intuitive concept trying to understand how to use it frankly makes my head spin. So instead I just wrote a simple function. If someone can tell me why using an IViewCursor is better or easier than the following function I would like to hear it ( and see an example ).

// returns the index position of object with matching usid value
private function usidSearch( usid:Number, coll:ArrayCollection ):Number
{
var o:Object;
for ( var i:Number = 0; i<coll.length; i++){
o = coll.getItemAt(i);
if( o.usid == usid) return i;
}
return -1;
}

Updated Flex PageList Component and Demo with Google JSON API

I've had a chance to completely re-write my PageList component so it runs much smoother and provides easier more flexible use.

The PageList component let's a user horizontally page through a TileList. The component binds with a HTTPService to provide a continual flow of data.

Click here to view a demo of the component

Click here for full source code

Things to make note of:

Because the component dynamically adjusts it's own X position it needs to be the child of either an Application, Canvas or Panel.

The component at the moment has a single results handler which handles a JSON response from a Google API. To use this component you can easily add your own handler functions to handle data specific to your own application.

Google JSON API

The demo I've put together for this component makes use of a Google JSON API which is really handy and easy to access if your Flex project uses the Adobe Corelib library.

The Google JSON API can be accessed via the following URLs.

http://www.searchmash.com/results/images:[query]
http://www.searchmash.com/results/blogs:[query]
http://www.searchmash.com/results/video:[query]

The full url I used in the demo is

http://www.searchmash.com/results/images:Apple

In order to access the API remotely and not run into any Flex security issues I used a php proxy. Click here for details

Monday, March 3, 2008

Embedding fonts via CSS in Flex

Just a handy little reference for embedding fonts via CSS in your Flex applications.

Label
{
embedFonts: true;
color: #FF0000;
fontFamily: YourFontFamily;
}