Skip Navigation

About This Website

CodeStore is all about web development. Mostly with the Lotus Domino server.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

Latest Comments

Elsewhere

More links are available in the archive »

Flex App Basics 10: The Form Container

We've talked about how to create a View component so it follows that we need a Form component to compliment it.

Let's take another look at the src folder of our Flex app. Notice I've added a folder called "forms" to keep each different form in -- one for the documents in the contacts view and one for the companies view.

image

These two forms are based on the Form.mxml component that you can see in the net.codestore.flex.* package/folder. This Form component contains all the things common between both the forms based on it. Things like the layout of the fixed-position button bar, the validation routine, the HTTP service to fetch and post the data from the server.

Let's look at the Contact.mxml code, as below:

image 

Notice how the main root tag is a Form. This means it is based on the Form component I mentioned. In the Form component I've defined 3 different objects that can be used to define the form -- content, buttons and the validators. Using these three properties of the Form we can quickly build a form without worrying about adding all the bits that are already in Form.mxml.

It's inside Form.mxml that we add the buttons and content in to the right place. It's also where we loop the array of validators at the point the form is submitted and prevent submission on failure.

Here's the code that runs when the Form element is first opened:

[Bindable]
public var validators:Array;

[Bindable]
public var content:Container;

[Bindable]
public var buttons:Array;

private function initForm():void{

 //Add each of the buttons passed to the form in to the action bar
 buttons.forEach(function(element:*, index:int, arr:Array):void{
  bar.addChild(element);
 });

 //Add the main form container in to the right place.
 formContainer.addChild(content);
}

That should give you an idea how it works. Notice the three public bindable properties, which we used to define the main elements of the form.

How To Open a Form

From some place in our script, say in the double-click event of the view, all we have to do in order to open a document using one of our forms is run code like this:

import forms.*;

private function openDocumentInTab(id:String):void{
 var form:Contact = new Contact();
 form.isNewDoc = false;
 form.documentUnid  = id;
 
 //Add it to the tabbed navigator
 tabs.addChild(form);
}

Because we've told it to import everything in the src/forms/ folder we can then create objects of the type "Content" (or "Company") as if they were built-in components. Thus we have access to the public properties of the objects, such as isNewDoc and documentUnid.

Obviously there's more to it than this, but hopefully you'll get the idea? The concept it quite simple and works quite well. If you need to alter the behaviour of the underlying Form element then you can do and the change will apply to all "forms" built on it.

What Next?

I think I've had enough of this Flex App Basics series of articles and I'm sure you probably have. I'm not even sure they've followed enough of a pattern to call them a series anything. They're more like random jottings that don't really piece together too well. Hopefully they'll have given you ideas on different methodologies though.

On Monday I'll package all the Contact Manager code together and upload it here. While it's nowhere near being a finished app it's good enough for you to rip apart and learn from. If I get the time to I'll try to keep adding on top of it.

Comment Icon 3/3 Comments Read - Add | Fri 5 Feb 2010 | Open »

Flex App Basics 9: Creating an Icon Library

To include an icon in a Flex component you can simply embed it like below:

<mx:LinkButton label="Button with an Icon" icon="@Embed('../images/anicon.png')" />

While this works, it can get messy and cumbersome maintaining the set of icon files. Especially if you change your folder structure and all embedded images break. Not only that but if you embed the same icon in more than one place it takes up extra space (or so I believe) as each instance of the image is stored separately in the SWF.

A better idea is to have an icon library. This an idea I've adapted from this one. Once you get used to using a "library" there's no going back.

Here's the folder structure for the Contact Manager app. Notice the folder structure for the net/codestore/flex package, which contains all the reusable custom components I've come up with, such as the View, SearchField and FileManager.

Within this "codestore" package is a resources folder, which contains an icons folder, which, in turn, contains the silk folder with all 700+ Silk icons from FamFamFam.

image

Then there's the IconLibrary.as file, which looks a bit like this:

package net.codestore.flex
{
    [Bindable]
    public class IconLibrary
    {               
                        
        [Embed (source="resources/icons/silk/disk.png")]
        public static const SAVE_ICON:Class;
        
        [Embed (source="resources/icons/silk/bullet_disk.png")]
        public static const SAVE_SMALL_ICON:Class;
        
        [Embed (source="resources/icons/silk/cross.png")]
        public static const CROSS_ICON:Class;
        
        [Embed (source="resources/icons/silk/exclamation.png")]
        public static const ERROR_ICON:Class;
        
        [Embed (source="resources/icons/silk/error.png")]
        public static const WARNING_ICON:Class;
        
        [Embed (source="resources/icons/silk/information.png")]
        public static const INFO_ICON:Class;
    }
}

What this gives us a quick and easy way to get to just the Silk icons we want. The LinkButton from above would now look like this:

<mx:LinkButton label="Button with an Icon" icon="{IconLibrary.CROSS_ICON}" />

No need to remember if they're there or what they're called as Flex provides us with type-ahead on the IconLibrary class. If the icon you're after isn't in the library you just add a new entry for it in the IconLibrary.as file. It's then available across the whole app.

Taking it Further

You're not limited to the Silk icons, of course. Remember the attachment manager component I talked about? Notice how each file has an associated icon:

To do this I added a set of icons to a "filetypes" folder you can see above -- one for each of the common files types. In the library code I then added a method called getIconForFileName() which looks a bit like this:

public static function getIconForFileType(type:String):Class{
 var icon:Class;
 type = type.toUpperCase();
                
 if (type=="DOC" || type=="DOCX"){
  icon = IconLibrary.FILE_DOC_ICON;     
 } else if (type=="XLS" || type=="XLSX" ){
  icon = IconLibrary.FILE_XLS_ICON;     
 } else {
  icon = IconLibrary.FILE_DEFAULT_ICON;
 }
                
 return icon;   
} 

public static function getIconForFileName(fileName:String):Class{
 var tmp:Array = fileName.split(".");   
 return getIconForFileType(tmp[tmp.length-1]);
}

The Repeater that displays attachments on the form then has an easy way of getting an icon to show for the tile it represents.

You could take it even further than this if needed. I know I probably will.

Don't leave home without your IconLibrary!

Comment Icon 1 Comments Read - Add | Thu 4 Feb 2010 | Open »

Flex App Basics 8: Display Column Values As Icons

As Notes/Domino developers we're used to being able to display icons in Views fairly easily. You just tick a box on the column properties and make sure the column value equals a number, which ties to the icon you want to show.

image

Not sure why I bored you with that bit. You all knew that already, didn't you.

Flex Alternative

How do we do implement a column icon in Flex though? Using a custom column renderer, that's how.

First thing to do is create a new custom Component. I created a file in Flex Builder at /src/net/codestore/flex/ColumnIconRenderer.mxml. The content of the file is below:

<?xml version="1.0" encoding="utf-8"?>
<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml" verticalAlign="middle" horizontalAlign="center">

        <mx:Script>
        <![CDATA[
                import net.codestore.flex.IconLibrary;
                
                [Bindable]
                private var _columnName:String;
                        
                public function set columnName(colName:String):void{
                	_columnName = colName;
                }
                        
                override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
                	super.updateDisplayList(unscaledWidth, unscaledHeight);
             
                	var tmp:Class = IconLibrary[data[_columnName].toString().toUpperCase()+'_ICON'];
                 
                	if (tmp is Class){
                         img.visible=true;
                         img.source = tmp;
                	} else { //Icon doesn't exist in library
                         img.visible = false;
                	}
                   
                }
        ]]>
    </mx:Script>
    
    <mx:Image id="img" />
</mx:Box>

The component is nothing more than a Box with an Image in the middle of it. We use the (very useful) method updateDisplayList which (as I understand it) gets called each time Flex renders or refreshes the display. In this method we look for an icon resource that matches the name specified in the column to which the renderer is tied. If the IconLibrary (more on that tomorrow) doesn't contain the icon specified we just hide the image.

Here's an example of the XML I'm sending to the Contact Manager database to use an Icon Column:

 image

Notice the parts I've highlighted. I've defined a column called "Attachments" to go at the end of the view, which is of type "icon" and is tied to the <file_icon> node of each document. For any document that has an attachment the value will be paper_clip and the result looks like this:

image

The only other part to this is that you need to apply this new custom column renderer to the column of the grid. To do this, in the ActionScript that loads the XML and creates all the columns there's the following bit of code:

if (column.hasOwnProperty("@type") && column.@type=="icon"){
 var iconRenderer:ClassFactory = new ClassFactory(net.codestore.flex.ColumnIconRenderer);
 iconRenderer.properties = {
  columnName: column.valueOf()
 };
 
 col.itemRenderer = iconRenderer;
 col.width=20;
 col.resizable=false;
}

In this bit of code the column object represents the <column> node I mentioned above, where type="icon". Notice that we're passing column.valueOf() to the columnName property of the renderer. The valueOf() the column node will be "file_icon" in this case and tells the renderer which child node to get its value from for each document.

All we need to do then is set the column's width and make it fixed. Hey, presto. It works.

It goes without saying, you're not limited to one type of icon per column or one icon column per view. You can have as many columns showing as many different icons as you choose -- just like in Notes! The beauty of this componentized, server-based XML approach being that it's all controlled from within your NSF and doesn't involve re-compiling any Flash SWFs.

Comment Icon 1/4 Comments Read - Add | Wed 3 Feb 2010 | Open »

Flex: Bug In SummaryRow When Using XMLListCollections

Having just spent the best part of a day re-working a near-complete Flex app to use ArrayCollections instead of XMLListCollections as the data providers for an AdvancedDataGrid I have a simple piece of advice -- make your choice between the two wisely and make the choice before you start.

There's a bug in Flex which means you can't use SummaryRows with data grids that use an XMLListCollection as the data provider. Well, at least it seems like a bug to me. I've read a few people mention it online, but had no response to a question I posted on the topic or seen anything official on the matter.

Here's a demo to show what I mean. Use the buttons to load the same data but with different collection types:

Notice how the donation column only gets summarised for the ArrayCollection and not the XMLListCollection. To me this smells like a bug whereby Flex isn't casting the XML strings to a number properly when leaving it as XML, but it does when it converts the XML to Objects.

Retro-fitting an ArrayCollection can be a pain. If there's even the slimmest chance you you'll need to use SummaryRows then make sure to use an ArrayCollection from the off.

Comment Icon 2/2 Comments Read - Add | Tue 2 Feb 2010 | Open »

Mystery Of the Missing Java Agents

Something weird is happening with my Java Agents. Notes keeps randomly dropping it's "handle" on them.

If I create a WebQuerySave agent in Java it all works well until out of the blue I'll get an error like this:

HTTP Web Server: Lotus Notes Exception - Entry not found in index [/path.nsf/0/DOCID?SaveDocument]

If I remove the name of the Java agent from the Form it works fine. It seems to me like Domino is just forgetting the agent exists. Although, obviously, it does still exist. I can see/edit it in Designer.

The only solution I've found is to create a new Agent and paste the code from the forgotten agent to the new one and change the WQS event in the Form to the name of the new Agent. Simple renaming the old Agent doesn't work.

Needless to say this is very annoying. I'm starting to wonder why I didn't just stick with doing everything in LotusScript.

Anybody seen this behaviour before? I'm using Domino Designer 8.5.1 and the server is Domino 6.5.

To rub salt in the wound it's now happening with a Scheduled Java Agent which is telling me "Entry not found in index" in its log. Again, I had to create the agent from scratch.

Comment Icon 7/16 Comments Read - Add | Fri 29 Jan 2010 | Open »

More blog entries are available in the archive »