How to build a contact manager in AIR using XML – Part 2
by 17 July, 2008 11:36 pm8
Its finally time for the second part of the AIR Contact Manager.
In this second, and final, part we’ll be learning how to save and edit the file and how to setup the bindings between the xml and our component.
On a side note, we’ll be using the application storage folder to save the data because AIR doesn’t allow us to write to the application folder itself.
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" initialize="{init()}" layout="absolute" height="451" width="542"> <!-- // --> <mx:Script> <![CDATA[ import mx.collections.XMLListCollection; private var myXml:XML; private var myLoader:URLLoader; [Bindable] private var myContactsCol:XMLListCollection;
Note the introduction of the [Bindable] above ‘private var myContactsCol:XMLListCollection;’ this tells the Flex components that they can use this variable to listen to changes and to change it’s values.
public function init():void { var dataFile:File = new File('app-storage:/data.xml'); if(dataFile.exists){ var myReq:URLRequest = new URLRequest('app-storage:/data.xml'); myLoader = new URLLoader() myLoader.addEventListener(Event.COMPLETE, dataComplete); myLoader.load(myReq); }else{ createFile() } }
We start by initializing the application, as we saw in the previous part, but this time we need to check if the XML file already exists in our
application storage. And if it doesn’t we need to create it.
Note: You’ll notice that we’re referencing the file as app-storage:/data.xml, app-storage is a shortcut that AIR give you to your local storage location on the users machine.
private function createFile():void { var xmlToSave:XML = new XML('<flashEnabled><contacts>' + '<contact>' + '<name>Contact1</name>' + '<telephone></telephone>' + '<email></email>' + '</contact>' + '</contacts>' + '</flashEnabled>') var saveStr:String = xmlToSave.toXMLString(); var file:File = new File('app-storage:/data.xml'); var fs:FileStream = new FileStream(); fs.open(file, FileMode.WRITE); fs.writeUTFBytes(saveStr); fs.close(); init(); }
Since the file wasn’t found we’ll create it, we start by creating our base XML object and retrieving a string with xml identation, then we open a File reference to it and finally
we write the file using writeUTFBytes that will automatically save our string to the XML file with UTF-8.
private function dataComplete(e:Event):void { myXml = new XML(myLoader.data.toString()); myContactsCol = new XMLListCollection(myXml..contact); } private function updateList():void { myContactsCol = new XMLListCollection(myXml..contact.(name.toLowerCase().indexOf(search_txt.text.toLowerCase()) != -1 )) }
Here you’ll also notice that we no longer need to invalidate the list or reset the datagrid’s dataprovider, this is because we now use Binding.
private function saveData(e:Event):void { var xmlToSave:XML = new XML('<flashEnabled><contacts>'+myContactsCol.toXMLString()+'</contacts></flashEnabled>') var saveStr:String = xmlToSave.toXMLString(); var file:File = new File('app-storage:/data.xml'); var fs:FileStream = new FileStream(); fs.open(file, FileMode.WRITE); fs.writeUTFBytes(saveStr); fs.close(); }
This is where we’ll save the file, it’s essentially the same as create file, but with the contents of our current contact xml collection as nodes.
private function addItem():void { myContactsCol.addItem(new XML('<contact>' + '<name>Contact1</name>' + '<telephone></telephone>' + '<email></email>' + '</contact>')) } private function removeItem():void { myContactsCol.removeItemAt(myDg.selectedIndex); } ]]> </mx:Script>
Here we have the add and remove item from our collection. So first lets go over adding an item, we essentially need to create an empty node and add it to the xml collection.
This can be achieved in a myriad of ways, but I reckon this might be the easiest.
Then for the removing part it’s as easy as removing the item that corresponds to the current index of the data grid.
Design
<mx:DataGrid bottom="60" top="10" left="10" id="myDg" dataProvider="{myContactsCol}" editable="true" right="10"> <mx:columns> <mx:DataGridColumn headerText="Name" dataField="name"/> <mx:DataGridColumn headerText="Telphone" dataField="telephone"/> <mx:DataGridColumn headerText="Email" dataField="email"/> </mx:columns> </mx:DataGrid> <mx:Label x="10" text="Search:" bottom="10"/> <mx:TextInput x="65" id="search_txt" bottom="10"/> <!-- Code block 9 --> <mx:Button x="233" label="Go!" id="go_btn" click="{updateList()}" bottom="10"/> <mx:Button label="Save" click="{saveData(event)}" id="saveButton" bottom="10" right="10"/> <mx:Button x="286" label="Add" click="{addItem()}" bottom="10"/> <mx:Button x="343" label="Remove" click="{removeItem()}" bottom="10"/> </mx:WindowedApplication>
With all the UI elements in place we can now set the two properties we need for the datagrid to work properly, the editable=”true” so that we can edit the contents of each item,
and the to set the dataprovider to myContactsCol so that it will bind to it.
Afterward we just have the normal buttons and layout to call the appropriate methods on click and you’re all set.
I hope that this will help you get some insight on how to use Bindings and how to modify and write files using AIR so that you can apply it to your own projects,
in the previous part of this article we mentioned the application self update, but since then Adobe has release the air update framework and therefore there’s no longer
need to use our own library to achieve a self updating application.
If you have any questions feel free to expose them here and I’ll address them as soon as I can.