Friday, March 25, 2011

Create a log application using XML and AIR: Part 4

In today's tutorial we will add a feature that lets the user edit the existing logs in our AIR application.

Create a new button component object on stage and call it editEntryButton. Put it next to the deleteEntryButton.

First of all add the listener for the button.

editEntryButton.addEventListener(MouseEvent.CLICK, editEntry);

We also need to add a new boolean variable, that is true when user is editing an existing entry. This is necessary, because we use the same field and button for creating AND editing logs.

var editingEntry:Boolean = false;

Now, we need to turn the button invisible and visible the same way like we did with the deleteEntryButton.

In the selectEntry function:

function selectEntry(evt:Event):void
{
myDescription.text = evt.target.selectedItem.data;
deleteEntryButton.visible = true;
editEntryButton.visible = true;
}

And in the updateList function:

function updateList():void
{
myList.dataProvider = new DataProvider();
for (var log in localXML.logentry)
{
myList.addItem({label: "Log entry: " + localXML.logentry[log].@date, data: localXML.logentry[log]});
}
deleteEntryButton.visible = false;
editEntryButton.visible = false;
myDescription.text = "";
}

Now, what happens when we click the edit button (editEntry function). We want the myText field to get the text that is in the myDescription field (the information the log contains at the moment), then we want the myDescription field to become blank itself, and the list and both buttons turn disabled, so that we can't do anything else when editing an entry. We also set the editingEntry to true.

function editEntry(evt:MouseEvent):void
{
myText.text = myDescription.text;
myDescription.text = "";
myList.enabled = false;
deleteEntryButton.enabled = false;
editEntryButton.enabled = false;
editingEntry = true;
}

Now we'll need to add some stuff to the writeEntry function - the one that is called when we press the Submit entry button.

When we press that button, we need to check for the editingEntry variable's value. If it is false - write a new entry. If it is true - edit the current one. When editing an existing log, we change its value to the one that's entered in the text field. After that we change the myDescription text value to the new value and set myText to blank. We re-enable all the buttons and the list component. Finally, we saveXML() and set the editingEntry variable to true.

function writeEntry(evt:MouseEvent):void
{
if (! editingEntry)
{
localXML.appendChild({myText.text});
myText.text = "";
updateList();
saveXML();
}
else
{
localXML.logentry[myList.selectedIndex] = myText.text;
myDescription.text = myText.text;
myText.text = "";
myList.enabled = true;
deleteEntryButton.enabled = true;
editEntryButton.enabled = true;
saveXML();
editingEntry = false;
}
}

Here's the full code:

import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.events.MouseEvent;
import flash.events.Event;
import fl.data.DataProvider;

var myFile:File = File.documentsDirectory.resolvePath("Air Examples/mylog.xml");
var localXML:XML;
var editingEntry:Boolean = false;
myText.text = "";

getXML();
updateList();

myWriteButton.addEventListener(MouseEvent.CLICK, writeEntry);
deleteEntryButton.addEventListener(MouseEvent.CLICK, deleteEntry);
editEntryButton.addEventListener(MouseEvent.CLICK, editEntry);
myList.addEventListener(Event.CHANGE, selectEntry);

function getXML():void
{
if (myFile.exists)
{
var myStream:FileStream = new FileStream();
myStream.open(myFile, FileMode.READ);
localXML = new XML(myStream.readUTFBytes(myStream.bytesAvailable));
myStream.close();
}
else
{
localXML = <mylog></mylog>;
}
}

function saveXML():void
{
var myStream:FileStream = new FileStream();
myStream.open(myFile, FileMode.WRITE);
myStream.writeUTFBytes(localXML.toXMLString());
myStream.close();
}

function selectEntry(evt:Event):void
{
myDescription.text = evt.target.selectedItem.data;
deleteEntryButton.visible = true;
editEntryButton.visible = true;
}

function updateList():void
{
myList.dataProvider = new DataProvider();
for (var log in localXML.logentry)
{
myList.addItem({label: "Log entry: " + localXML.logentry[log].@date, data: localXML.logentry[log]});
}
deleteEntryButton.visible = false;
editEntryButton.visible = false;
myDescription.text = "";
}

function writeEntry(evt:MouseEvent):void
{
if (! editingEntry)
{
localXML.appendChild(<logentry date={new Date()}>{myText.text}</logentry>);
myText.text = "";
updateList();
saveXML();
}
else
{
localXML.logentry[myList.selectedIndex] = myText.text;
myDescription.text = myText.text;
myText.text = "";
myList.enabled = true;
deleteEntryButton.enabled = true;
editEntryButton.enabled = true;
saveXML();
editingEntry = false;
}
}

function deleteEntry(evt:MouseEvent):void
{
delete localXML.logentry[myList.selectedIndex];
updateList();
saveXML();
}

function editEntry(evt:MouseEvent):void
{
myText.text = myDescription.text;
myDescription.text = "";
myList.enabled = false;
deleteEntryButton.enabled = false;
editEntryButton.enabled = false;
editingEntry = true;
}

Thank you for reading!

Related:

Files and directories in AIR: Part 1
Files and directories in AIR: Part 2
Files and directories in AIR: Part 3
Files and directories in AIR: Part 4
Files and directories in AIR: Part 5
Files and directories in AIR: Part 6
Files and directories in AIR: Part 7
Files and directories in AIR: Part 8
Files and directories in AIR: Part 9
Files and directories in AIR: Part 10
Files and directories in AIR: Part 11
Create a log application using XML and AIR: Part 1
Create a log application using XML and AIR: Part 2
Create a log application using XML and AIR: Part 3
Files and directories in AIR: Part 12

7 comments:

Andre said...

Sorry to post, I do yet dont have the know how to achieve this with a local xml thru FileReference. I´m trying to use something similar to your code, below the functions, when I try to save the local xml is not saving the changes that the user make on function “texto_painel_change”, I really dont know how to transfer the content typed in the function “item_click” to the function “salvar_xml_click”, if you please could give a hand:

salvar_xml.addEventListener(MouseEvent.MOUSE_DOWN, salvar_xml_click)
function salvar_xml_click(e:MouseEvent):void
{
var file:FileReference = new FileReference();
file.save(xml,”.xml”);
texto_painel.htmlText;
FileFilter(“Documents”,”*.xml”);
}

myGrid.addEventListener(MouseEvent.CLICK, item_click)
function item_click(e:Event):void
{
texto_painel.htmlText = myGrid.selectedItem.label;
}

texto_painel.addEventListener(Event.CHANGE, texto_painel_change)
function texto_painel_change(e:Event):void
{
myGrid.selectedItem.label = texto_painel.htmlText;
}

Kirill Poletaev said...

I don't really understand what do you need help with, can you rephrase your question?

If you need to pass values from one function to another, just store the value in a global variable that you can read and write to.

Andre said...

Kirill thank you for your time, my needs are:
//Here I load a local XML into a DataGrid
function carrega_topico(e:Event)
{
myGrid.removeColumnAt(1);
xml = new XML(e.target.data);
trace(xml.telas.tela.length());
myGrid.dataProvider = new DataProvider();
myGrid.spaceColumnsEqually();
for(var i=0;i<xml.telas.tela.length();i++)
{
myGrid.addItem({Numero:[i],label:xml.telas.tela.texto[i]});
myGrid.editable=false;
}
}
//WHen user click the DataGrid it show on a TextArea the XML content
myGrid.addEventListener(MouseEvent.CLICK, item_click)
function item_click(e:Event):void
{
texto_painel.htmlText = myGrid.selectedItem.label;
trace(myGrid.selectedItem.label);
}
//When user make any modification into the loaded XML on TextArea this value is update into the DataGrid
texto_painel.addEventListener(Event.CHANGE, texto_painel_change)
function texto_painel_change(e:Event):void
{
myGrid.selectedItem.label = texto_painel.text;

//Here is my problema im only know how to send to a especific node and not the one that I´ve make the modification, thats it...!

xml.telas.tela.texto[1] = texto_painel.text;
}
//Saving the XML local
salvar_xml.addEventListener(MouseEvent.MOUSE_DOWN, salvar_xml_click)
function salvar_xml_click(e:MouseEvent):void
{
var file:FileReference = new FileReference();
file.save(xml,".xml");
}

Thank you for your time...

Kirill Poletaev said...

You created a Numero attribute when adding items:

myGrid.addItem({Numero:[i],label:xml.telas.tela.texto[i]});

You can use it now:

xml.telas.tela.texto[myGrid.selectedItem.Numero] = texto_painel.text;

Andre said...

Great, you are a master...

Andre said...

Kirill, you already help me a lot, and I´m into another challenge here, we make the changes be added to the local XML, but now I´m tryng thru this TextArea,is to make the selected text became "bold" when the user press the bold_mc, what I came up until now is this:

bold_mc.addEventListener(MouseEvent.CLICK, bold_style)
function bold_style(e:MouseEvent):void
{
var selected_texto:int = (texto_painel.selectionBeginIndex, texto_painel.selectionEndIndex)
texto_painel.htmlText = "+selected_texto+""
}

Kirill Poletaev said...

You are using htmlText, so you can turn text into bold by adding the bold html tags. See my tutorial on that here.

Post a Comment