Home > Flex > Provide a Flex itemEditor with dynamic data

Provide a Flex itemEditor with dynamic data

When your Flex application needs an editable datagrid, you mostly add some itemEditors or itemRenderers to change the data.
You can find a lot of samples on the web, although it is not always that easy as most of them show.

This post shows a solution when you need an itemEditor that needs data different from the itemEditor its data property.

You can see an example of this blog post behind this link.

Assume you have a service that returns a collection with objects that are instances of Person (properties: id – name – address – roleId). You want to display all this items in a datagrid. The roleId needs to be replaced by the roleName so we need to use a labelFunction.
Before you can use this function, you need a collection of the roles. This are instances of Role (properties: id – name).
Most of the time you will call the “getAllRoles” service in the begin of your application.

Your labelFunction:

private function getRoleName(person:Person, col:DataGridColumn):String
{
    for each (var role:Role in _roles)
    {
        if (role.id == person.roleId)
        {
            return role.name;
        }
    }
    return "Unknow role type";
}

But what if the “role” column needs to be editable. We want an itemEditor that shows us a combobox (or a dropDownList in Flex 4) with all the role names.
The problem is that the dataProvider of the comboBox/dropDownList needs to be filled with dynamic data.
Because I’m not a big fan of inline itemEditors, I give an example for a custom ItemEditor.

Custom ItemEditor for FLEX 4:

<?xml version="1.0" encoding="utf-8"?>
<s:MXDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
                          xmlns:s="library://ns.adobe.com/flex/spark"
                          xmlns:mx="library://ns.adobe.com/flex/mx">
    <fx:Script>
        <![CDATA[
            import domain.Person;
            import domain.Role;

            import mx.collections.IList;

            private var _person:Person;

            public function get roleId():int
            {
                return Role(ddlRoles.selectedItem).id;
            }

            override public function get data():Object
            {
                return super.data;
            }

            override public function set data(value:Object):void
            {
                super.data=value;

                //When the data changes we dispatch an event that bubbles
                dispatchEvent(new Event("itemEditorDataChange", true));

                _person=Person(value);

                //We select the correct role in the dropDownList
                ddlRoles.selectedIndex=getCurrentRoleIndex();
            }

            public function set dataProvider(value:IList):void
            {
                ddlRoles.dataProvider=value;
            }

            private function getCurrentRoleIndex():int
            {
                var numRoles:int=ddlRoles.dataProvider.length;
                for (var i:int=0; i < numRoles; i++)
                {
                    if (ddlRoles.dataProvider[i].id == _person.roleId)
                    {
                        return i;
                    }

                }
                return 0;
            }
        ]]>
    </fx:Script>

    <s:DropDownList id="ddlRoles"
                    width="100%"
                    labelField="name"/>

</s:MXDataGridItemRenderer>

Note: You could use the mx:ComboBox instead of the MXDataGridItemRenderer.

The application with the datagrid for FLEX 4:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx"
               creationComplete="onCreationComplete()">

    <fx:Script>
        <![CDATA[
            import domain.Person;
            import domain.Role;

            import mx.collections.ArrayCollection;

            [Bindable]
            private var _people:ArrayCollection;

            private var _roles:ArrayCollection;

            private function onCreationComplete():void
            {
                loadRoles();
                loadPeople();

                //Add a listener that listens to the custom data change event that bubbles from the custom item editor
                dgrItems.addEventListener("itemEditorDataChange", onDataChange);
            }

            private function onDataChange(event:Event):void
            {
                var itemEditor:RoleItemEditor=RoleItemEditor(event.target);
                itemEditor.dataProvider=_roles;

            }

            private function loadRoles():void
            {
                //Normally you get your roles collection from a backend service
                //For this sample we just create a roles collection
                _roles=new ArrayCollection([new Role(1, "Super Admin"), new Role(2, "Admin"), new Role(3, "Member")]);
            }

            private function loadPeople():void
            {
                //Normally you get your people collection from a backend service
                //For this sample we just create a people collection
                _people=new ArrayCollection([
                    new Person(1, "Wannes", "Antwerp", 1),
                    new Person(2, "Tom", "Brussels", 2),
                    new Person(3, "Steve", "London", 3),
                    new Person(4, "Stephane", "Paris", 2),
                    new Person(5, "Jack", "Sydney", 3),
                    ]);
            }

            private function getRoleName(person:Person, col:DataGridColumn):String
            {
                for each (var role:Role in _roles)
                {
                    if (role.id == person.roleId)
                    {
                        return role.name;
                    }
                }
                return "Unknown role type";
            }
        ]]>
    </fx:Script>

    <s:layout>
        <s:VerticalLayout verticalAlign="middle"
                          horizontalAlign="center"/>
    </s:layout>

    <mx:DataGrid id="dgrItems"
                 dataProvider="{_people}"
                 width="80%"
                 editable="true"
                 height="200">
        <mx:columns>
            <mx:DataGridColumn dataField="id"
                               headerText="Id"/>
            <mx:DataGridColumn dataField="name"
                               headerText="Name"/>
            <mx:DataGridColumn dataField="address"
                               headerText="Address"/>
            <mx:DataGridColumn dataField="roleId"
                               headerText="Role"
                               itemEditor="RoleItemEditor"
                               editorDataField="roleId"
                               labelFunction="getRoleName"/>
        </mx:columns>
    </mx:DataGrid>

</s:Application>

And again, click here to view a working sample! (View source is enabled).

Categories: Flex Tags: , , ,
  1. Algo
    July 16th, 2010 at 13:40 | #1

    Hello,

    I did same approach for spark ComboBox, but with long drop down values like this

    _roles=new ArrayCollection([
    new Role(1, "Super Admin"),
    new Role(2, "Admin"),
    new Role(3, "Member1"),
    new Role(4, "Member2"),
    new Role(5, "Member3"),
    new Role(6, "Member4"),
    new Role(7, "Member5"),
    new Role(8, "Member6"),
    new Role(9, "Member7"),
    new Role(10, "Member8"),
    new Role(11, "Member9"),
    new Role(12, "Member10"),
    new Role(13, "Member11"),
    new Role(14, "Member12"),
    new Role(15, "Member13"),
    new Role(16, "Member14"),
    new Role(17, "Member15"),
    new Role(18, "Member16"),
    new Role(19, "Member17"),
    new Role(20, "Member18"),
    new Role(21, "Member19"),
    new Role(22, "Member20"),
    new Role(23, "Member21"),
    new Role(24, "Member22"),
    new Role(25, "Member23"),
    ]);

    I face problem with long list of dropdown values, when I try to click the scrollbar of the ComboBox, the drop down values suddenly disappear, I have searched solution around and around but I cannot find any suggestion yet, here is the similar post: http://forums.adobe.com/thread/630554?tstart=1

    it says that:
    the scrollbar skin is not considered a child of the datagrid so clicking on it causes the datagrid to run the endEdit event, closing the editor

    regards

  2. james
    October 11th, 2010 at 01:19 | #2

    That’s exactly what I was looking for…thanks. Keep it up

  1. No trackbacks yet.
Security Code: