Tuesday 14 July 2009

Categorised Views in Flex - It's really easy

OK .. a Flex Post for youse in Domino land.

First some stuff about the what I used.

Flex 3 SDK
Notepad ++
Domino 8.5.0 server
Domino 8.5.0 DDE

I was asked recently how I would FLEX a multi-category expand/collapsible view which is admittedly dead easy in the Notes Client. Well it is almost as easy in Flex.

This is what I did to illustrate the method.

01. I created a form that looks like this


02. I created a view that looks like this

03. I created an agent that does this
04. I opened Notepad++ and created a file called CategoryView1.mxml and typed up these 47 lines of code
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="myData.send()">
<mx:HTTPService id="myData"
url="http://www.unseenuni.com:81/flexview.nsf/getdata?openagent"
result="dataResult(event)"/>
<mx:Script>
<![CDATA[
import mx.controls.Text;
import mx.controls.Alert;
import mx.rpc.events.ResultEvent
import mx.collections.ArrayCollection
[Bindable]
private var items:ArrayCollection = new ArrayCollection
private var msg:String
private function dataResult(event:ResultEvent):void
{
items= event.result.items.item;
myGroup.refresh(true)
}
private function dostuff(event:MouseEvent):void
{
if(event.target.data.key)
{
msg = event.target.data.key
mx.controls.Alert.show(msg)
}
}
]]>
</mx:Script>

<mx:AdvancedDataGrid x="10" y="10" id="Grid1" designViewDataType="tree" width="719" height="343" creationComplete="myGroup.refresh()">
<mx:dataProvider>
<mx:GroupingCollection id="myGroup" source="{items}">
<mx:Grouping>
<mx:GroupingField name="cat"/>
<mx:GroupingField name="subcat"/>
</mx:Grouping>
</mx:GroupingCollection>
</mx:dataProvider>
<mx:columns>
<mx:AdvancedDataGridColumn headerText="Item" dataField="item"/>
<mx:AdvancedDataGridColumn headerText="Qty" dataField="qty"/>
<mx:AdvancedDataGridColumn headerText="Price" dataField="price"/>
</mx:columns>
</mx:AdvancedDataGrid>

</mx:Application>

05. I compiled up the mxml to a SWF using the SDK (a lot easier if you use FLEX BUILDER!)

06. I Imported the resulting file CategoryView1.swf as a File Resource in my NSF

07. I created a Page in my NSF with this Passthru HTML
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
id="CategoryView1" width="100%" height="100%"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="CategoryView1.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<param name="allowScriptAccess" value="sameDomain" />
<embed src="CategoryView1.swf" quality="high" bgcolor="#869ca7"
width="100%" height="100%" name="CategoryView1" align="middle"
play="true"
loop="false"
quality="high"
allowScriptAccess="sameDomain"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>
</object>

08. I fired up a browser and went to the page's I just created URL and this is what appeared.



It really is that easy... So lets look at this in detail.

The Domino agent returns nice simple XML - have a look at ../flexdata.nsf/getdata?openagent and you will see it in "raw" form, althought the parent view is sorted it is not categorised it is an ordinary flat view. We will let Flex do the sorting and grouping once it gets the data.

The MXML is only 47 lines long and was created as follows :-
(replace [] with < adn >)
01. I created an application

[mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"]

[/mx:Application]


This defines the application and it is always like this, note the tag pair is closed!


02. Inside the application tags I place a definition of the HTTPService I am going to use to provide the data to the application


[mx:HTTPService id="myData"
url="http://www.unseenuni.com:81/flexview.nsf/getdata?openagent"
result="dataResult(event)"/]


This breaks down into
id this is the id by which I will refer to the service later in the code
url this is the URL which will provide the data
result this is the actionscript code that will run when data is recieved from the url

03. The next section is the Actionscript code that my flex application will use

<mx:Script>
<![CDATA[
import mx.controls.Text;
import mx.controls.Alert;
import mx.rpc.events.ResultEvent
import mx.collections.ArrayCollection
[Bindable]
private var items:ArrayCollection = new ArrayCollection
private var msg:String
private function dataResult(event:ResultEvent):void
{
items= event.result.items.item;
myGroup.refresh(true)
}
]]>
</mx:Script>


Firstly I import the various Adobe Supplied libaries that i will need
Then I create a Bindable ArrayCollection object call items, this will store the returned data.
Then I define the dataResult() function that I attached to the HTTPService object. Remember this code gets executed when the URL in the HTTPService recieves data from the URL. In this instance the items ArrayCollection is loaded with the data returned from the URL. FLEX will see it as XML and I can access it through the event.result object by name.

04. Now I define my on screen objects

<mx:AdvancedDataGrid x="10" y="10" id="Grid1" designViewDataType="tree" width="719" height="343" creationComplete="myGroup.refresh()">
<mx:dataProvider>
<mx:GroupingCollection id="myGroup" source="{items}">
<mx:Grouping>
<mx:GroupingField name="cat"/>
<mx:GroupingField name="subcat"/>
</mx:Grouping>
</mx:GroupingCollection>
</mx:dataProvider>
<mx:columns>
<mx:AdvancedDataGridColumn headerText="Item" dataField="item"/>
<mx:AdvancedDataGridColumn headerText="Qty" dataField="qty"/>
<mx:AdvancedDataGridColumn headerText="Price" dataField="price"/>
</mx:columns>
</mx:AdvancedDataGrid>


I use the AdvancedDataGrid because it has support for Grouped (read Categorised Objects) you will not I do not ascribe a datasource to the AdvancedDataGrid Object. Instead I create a DataProvider object INSIDE the AdvancedDataGrid Tag pair! very important than!

Inside the DataProvider Object I create first a GroupingCollection object, I would do this even if I had only one category. Inside that I define a Grouping object and then as manu GroupingField objects as I need. In this instance the Fields Cat and SubCat.

I then define the Columns I want to display. Note i do NOT include the columns that will be my groups!

And that is it... compile it up, stick it in your NSF and Robert is your mother's brother.

I have uploaded the NSF and FLEX BUILDER PROJECT here.. but the NSF will not work on your server unless you change the URL in the MXML from my server to your own, recompile the SWF and delete the orginal SWF from the NSF and attach the new one as a new file resource.. i include it only so you can see the code not run it :-)

If you have any questions just drop me a line ... enjoy

Disqus for Domi-No-Yes-Maybe