Retrieving the new values while editing data inside the Data Grids

Maybe you like data grids as much as I do, or maybe you don’t like them at all. But either way, you decide one day that you want to use a data grid not only for displaying the data, but also for editing the data inline.

How do you do that? Or to rephrase the question, how do you get the new value once the user has finished editing one cell? If you search on the Internet, you will find different ways to do this. But somehow, they all seem to be less straightforward than you would expect.

I mean, when I first started to implement this behavior for an project I was working on, I expected to find an event that is dispatched by the data grid once the editing was finished. And using that event, I would access the old values and the new values. If you ever worked with triggers in a relational database, you probably remember that inside of a trigger you can easily access the old row and the new row values (that is, the values before the update and after). Well, it turns out that with a Flex data grid things are not as straightforward as I expected.

First I started by looking at the events that a data grid can dispatch. From that long list, only the events involving item_and_something looked like they would satisfy my needs. And out of that, I pick the event itemEditEnd as the lucky winner. Now, if you register an event listener on this event and then you go in debug mode and inspect the event, you will find that the data property is still not updated. Instead, you will find the old value and there is no property such as newValue or something similar to easily get the new value. At the time when this event is dispatched, the data model used by the data grid isn’t updated.

The only way I found to get the new data is to do something like this:

private function editListener(event:DataGridEvent):void {
    //get the data grid component     
    var dataGrid:DataGrid = event.target as DataGrid;
    //get the column object 
    var col:DataGridColumn = dataGrid.columns[event.columnIndex];
    //use the column object and data grid itemEditorInstance property to retrieve the new value
    var newValue:String = dataGrid.itemEditorInstance[col.editorDataField];
    //get the old value
    var oldValue:String = event.itemRenderer.data.toString();
}

While this code isn’t complicated, it’s not simple either. This leaves me with two questions:

  1. If you ever edited inline of a data grid, how did you do it?
  2. Why doesn’t the data grid have an event that just offers the old and new value when one cell is edited? I’ve just submitted a feature request for the Flex SDK for this one: https://bugs.adobe.com/jira/browse/SDK-16680 If you have the time, maybe you can vote for it.

Here is a small project sample to try the code.

UPDATE

A friend poited me out, that Peter Ent wrote about this too: http://weblogs.macromedia.com/pent/archives/2008/06/itemeditors_-_p_1.html

360|Flex and AMP

If you haven’t the chance to participate in a 360|Flex conference, you can watch 15 sessions from one event using AMP (Adobe Media Player). It is very simple:

  1. Install AMP
  2. Click “My Favorites” menu at the top.
  3. Click “Add RSS Feed” at the bottom.
  4. Paste: http://sessions.onflex.org/1733261879.xml

Enjoy!

Do you want a ticket to "Flash on the Beach" for free?

Between 28th September - 1st October it will be the Flash on the Beach conference in Brighton, UK. This is the third edition and it is a conference that you shouldn’t skip. Now, you have the chance to win a free ticket (a £499/€633 value). You have to send us a photo that is with you, and has a beach theme, and shows the love for Flash/Flex/AIR. And we will choose the winners - because we have 6 tickets to give it away!

Serje Jespers is collecting the photos via his blog. And each one of the six European platform evangelists will choose one winner: Andrew Shorten, Enrique Duvos, Serje Jespers, Cornel Creanga, myself and Mihai Pricope. We will announce the winners starting with 8th September.

Good luck people, and start making photos if you don’t have!

Paging a Data Grid on the client

My wife says that lately I have become obsessed, with data grids. Well, who am I kidding? While my wife is a psychologist and she does care about obsessions, she doesn’t care about Flex components. Anyway, the first time I saw a Flex data grid filled with items I asked myself: “What if I need to display more than 20 rows of data at the same time?” What visual hints, what UI should I use, to give the viewer a sense of what items he is looking at, how many there are left to see, and so on. Let’s take a look at it; here’s a data grid filled with a lot of data:

Flex data grid

When I was a web developer with InterAKT Online, I worked on a product called NeXTensio list. This product was an extension for Dreamweaver, and it was used for generating lists from a table or from a query, and it provided navigation buttons and other visual items to help you view and edit the list items.

So, it is no wonder that, as soon I had some time to play, I started to build a Flex component that adds some interesting behavior to a data grid. You can see here the whole thing put it together, and you can download the project from here (in the root of the ZIP file there is a readme.txt file that explains how to setup the project). About my application:

Here is a screen shot of the application:

Paging Data Grid Application on Client

How did I do it? Well, it wasn’t hard, but neither was it easy. The whole paging component is a custom Flex component (see the Paging.mxml file). All it needs is a reference to the data grid to which you want to add paging. You can configure how many buttons to render at the same time for moving through pages (I used 5 in my example). The trickiest part was to find how many items are displayed at one time in the data grid. When a data grid is initialized, the property rowCount from the data grid is 7, regardless of how many items are in the data grid. So, I need to have a listener registered on the data grid that it is triggered when rowCount changes. Because I couldn’t find an event for this, I ended up extending the data grid (see the MyDataGrid.mxml file) and I over-wrote the method setRowCount, to dispatch an event when rowCount changes.

For the rest of the story, have a look at the code and play with it. But please, don’t forget it isn’t production quality code, it’s just a proof of concept. Have fun!

LiveCycle Data Services 2.6 - new features

As you probably know, LCDS 2.6 was released last month. If you are not sure what new features it brings, or you want a more detailed description of them, you can look to my friend, Cornel Creanga, Blog posts here and here.

"30onMAX" or how to be in the MAX Keynote

If you want to be in the MAX Keynote, keep reading:) Adobe is putting together a video project of your videos called “30onMAX”. The selected videos will be used in MAX Keynote in San Francisco, Milan and Tokyo. To get there, you need to create a video on Why MAX?, upload the video on Youtube.com and tag it with “30onMAX”.

Duane’s World Episode 8

My friend Duane Nickull, (if you don’t know him, take a look at his blog), released episode 8 of his show. In this episode, you can watch interviews with Tim O’Reilly, John Markoff, Dries Buytaert and Bob Glushko.

Functional Testing Framework for AIR AJAX apps based on Selenium

My friends from the Romanian Adobe AIR team have been very busy lately. Marius and Alex have been working on, was to modifying Selenium so you can run automated / functional tests on AIR applications developed with HTML/JS.

To be honest, I am quite amazed about what they managed to pull off in so little time. And because we need your feedback, I have an archive ready for download here, so you can start playing with it in minutes. Here is what it is in ZIP:

  1. demo movies - two movies that show you the workflow supported for now
  2. sample tests - this is the interesting part. You have two applications and some tests files to test these applications with this framework. The first test uses a Selenium based model for dispatching UI events, the second uses a Java AWT robot to generate mouse and key events.
  3. selenium recorder - this lets you record your UI interaction with the application. Then with a little editing on the resulting test files you can create the test cases for your automated testing.
  4. selenium server - this is the heart of this framework. It acts as a proxy between the requests that are made from tests and the AIR application.
  5. readme.txt - for a quick start on trying the samples; this files describes how to create a Java project and run the tests from Eclipse as a JUnit Test Case.
  6. SeleniumWithAIR.pdf - the first draft of documentation for this framework, which includes the known issues.

It should work on Win and Mac, with Java 1.5 or newer and AIR SDK 1.1.

Here is a short explanation of how to quickly run the tests from the ZIP file:

  1. Download the ZIP, and unzip somewhere on your disk
  2. Create a system variable named ADL_EXE and set its value to the full path of the “adl” executable from your local AIR SDK
    Create ADT_EXE env variable
  3. Start the server: selenium/selenium server/runServer.bat
    The Selenium server is started
  4. Run the tests: selenium/sample tests/runTest.bat
    First test runSecond test run

Here is a snapshot of the Eclipse project to run the tests from the ZIP:

Running the tests from Eclipse

So, that’s it! Try these goodies and let me know what you think!

Extending ActionScript classes to provide AsyncToken like behavior

When you use a class from the Flex framework that does an asynchronous call, you can use the AsyncToken that the call returns to save values/objects that you need when the result event is triggered.

Let’s look at this code:

private function getData():void {
    //create a new HTTPService
    var myService = new HTTPService();
    //add event listener for result
    myService.addEventListener(ResultEvent.RESULT, resultListener);
    //save the async token
    var token:AsyncToken = myService.send();
    //add to token our own data
    token.myData = {name: "john doe", id : 1};
}

private function resultListener(event:ResultEvent):void {
    //retrieve from event.token our data
    myData:Object = event.token.myData;
}

So, we have two functions. The first, getData() creates a HTTPService, attaches an event listener for the result event, and then makes a call to the server. When it makes a call, an AsyncToken is returned. I can use this token to store some info I need in the result listener. The second function is the definition of the result listener. When this function is called, you can access the AsyncToken from the property token from event: event.token. Having the token, it is easy to retrieve the data that I stored when I made the call to the service.

Why is that useful? Sometimes you want to be able to associated some data to a particular call, so when result event is called, you are able to take a different actions based on the data passed.

Unfortunately, when you do a call to a class from Flash, for example, flash.net.URLLoader you don’t have this AsyncToken returned. Consider the following code:

var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, completeListener);
//this line does not working; the load() method is not returning anything
var token = loader.load(new URLRequest("http://mysite/pic.png));

How do you pass your data between the call and the result for objects that are not using AsyncToken? One simple way is to extend the object you want to use, and add one property to store an object. Let’s do this for the URLLoader class:

public class MyLoader extends URLLoader {

    private var _data:Object;

    public function MyLoader(data:Object) {
        super();
        this._data = data;
    }

    public function get data():Object {
        return this._data;
    }
}

Now, let’s see how you can use this object to do asynchronous calls and still be able to pass data:

var myData:Object = {name : "john doe", id : 9};
var loader:MyLoader = new MyLoader(myData);
loader.addEventListener(Event.COMPLETE, completeListener);
//make a request for an item from server
loader.load(new URLRequest("http://myste/pic.png));

//complete listener for loader
private function completeListener(event:Event):void {
    //retrieve the loader instance
    var myLoader:MyLoader = event.target;
    //retrieve the data object
    var myData:Object = myLoader.data;
}

When I create the custom loader object, I pass a reference to the data object that I want to retrieve when the loader has the response (this object is stored using the _data property from MyLoader). When the complete event is reached, using the target property on the event object, I retrieve the MyLoader object that made the call . Having the loader object, I can access the data property to retrieve the original data I stored.

ScaleNine "Skin to Win Challenge" - contest for Flex themes

If you know how to skin Flex apps, and you need one of these: Macbook AIR with SSD, Creative Suite 3, Flex Builder Professional or a ticket to MAX 2008, just go here and submit your best themes for Flex, and you might win!

Next Page →