Flex datagrid and nested Array dataprovider - apache-flex

I have used datagrid on many projects populate the grid using the following "Usual data structure" and brought the standard o/p as shown below Image.
But now for one assignment I want to bring the same grid result using the below mentioned "Complex data structure" (nested array). I have some Idea which is process the data before pushing it to the Grid but the problem am having is I need to perform some update , edit delete operation through the grid renderers and the same should be reflected into the source collection also. Please let me know is there a way I can use the "Complex structure" and bring the expected o/p using any flex in build properties. Thanks in Advance.
Usual data structure
steps = [a,b,c];
a = {x:100,y:y1,z:z1};
b = {x:200,y:y2,z:z2};
c = {x:300,y:y3,z:z3};
Complex data structure
[] is an Array collection not Array type.
a = [100,y1,z1];
b = [200,y2,z2];
c = [300,y3,z3];
steps = [[a,some objects],[b,some objects],[c,some objects]];
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private var a:ArrayCollection = new ArrayCollection(['x1','y1','z1']);
private var b:ArrayCollection = new ArrayCollection(['x2','y2','z2']);
private var c:ArrayCollection = new ArrayCollection(['x3','y3','z3']);
[Bindable]
private var stepsObjs:ArrayCollection = new ArrayCollection([{ items: a},{ items: b},{ items: c}]);
]]>
</mx:Script>
<mx:DataGrid dataProvider="{stepsObjs}" >
<mx:columns>
<mx:DataGridColumn dataField="items.0" headerText="x" />
<mx:DataGridColumn dataField="items.1" headerText="y" />
<mx:DataGridColumn dataField="items.2" headerText="z" />
</mx:columns>
</mx:DataGrid>
</mx:Application>

EDIT Replacing with code to solve the new question.
This one worked for me:
<?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" minWidth="955" minHeight="600"
>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private var a:ArrayCollection = new ArrayCollection([100,'y1','z1']);
private var b:ArrayCollection = new ArrayCollection([200,'y2','z2']);
private var c:ArrayCollection = new ArrayCollection([300,'y3','z3']);
private var stepsObjs:ArrayCollection = new ArrayCollection([{ items: a},{ items: b},{ items: c}]);
private var stepsColl:ArrayCollection = new ArrayCollection([[a],[b],[c]]);
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout />
</s:layout>
<mx:DataGrid dataProvider="{stepsObjs}" >
<mx:columns>
<mx:DataGridColumn dataField="items.0" headerText="x" />
<mx:DataGridColumn dataField="items.1" headerText="y" />
<mx:DataGridColumn dataField="items.2" headerText="z" />
</mx:columns>
</mx:DataGrid>
<mx:DataGrid dataProvider="{stepsColl}" >
<mx:columns>
<mx:DataGridColumn dataField="0.0" headerText="x" />
<mx:DataGridColumn dataField="0.1" headerText="y" />
<mx:DataGridColumn dataField="0.2" headerText="z" />
</mx:columns>
</mx:DataGrid>
</s:Application>

The itemRenderers should dispatch an event that describes what should happen, and then it should be handled higher up.
Like this:
//inside item renderer
dispatchEvent(new ItemEvent(ItemEvent.DELETE_ITEM, true, item));//where true tells the event to bubble (you'll need to create this event)
//somewhere above the DataGrid
dataGrid.addEventListener(ItemEvent.DELETE_ITEM, deleteItemFromSource);
protected function deleteItemFromSource(e:ItemEvent):void {
var lcv:ListCollectionView = (dataGrid.dataProvider as ListCollectionView);
lcv.removeItemAt(lcv.getItemIndex(e.item));
}
Note as a FYI that you should be using some sort of ListCollectionView if you want the datagrid to automatically update when you change it, not an Array.
HTH;
Amy

Related

Flex datagrid header row right click

I got a Datagrid in my Flex application.
I need to make appear a context menu when the header row is right-clicked.
The latter context menu must not appear when the rest of the datagrid items (the ones containing data) are clicked.
Edit: the application runs in AIR environment, so i got no flash-player troubles
In flex, and more generally in flash, there is no way to catch the the right click event.
I'm not sure about the right mouse click, cos flex apps run in flash player, and right click brings up its menu.
The best bet would be to use headerRelease event on your DatagRid. In your event handler you can then create your menu (maybe in a popup or some hovering panel?) and then do what you need to do there.
Read more about it here
edit:
Maybe you could use a contextMenu class, and attach it to your dataGrid.contextMenu?
Below code may help you: -
I have created sample in which i have added only one ITEM. You can convert it and change logic as per requirement. My idea is to provide one of the base logic. You may gey better solution but this can work for you.
<?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" minWidth="955" minHeight="600"
>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<mx:DataGrid id="myDG" width="350">
<mx:dataProvider>
<mx:ArrayCollection>
<mx:source>
<fx:Object Artist="" Price="11.99"
Album="Slanted and Enchanted" />
<fx:Object Artist=""
Album="Brighten the Corners" Price="11.99" />
</mx:source>
</mx:ArrayCollection>
</mx:dataProvider>
<mx:columns>
<mx:DataGridColumn dataField="Artist" headerRenderer="StackLabelRenderer"/>
<mx:DataGridColumn dataField="Album" headerRenderer="StackLabelRenderer"/>
<mx:DataGridColumn id="price" dataField="Price" headerRenderer="StackLabelRenderer"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
StackLabelRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Label xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
click="dispatchClickEvent()">
<fx:Script>
<![CDATA[
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.controls.dataGridClasses.DataGridListData;
import mx.core.mx_internal;
private function dispatchClickEvent():void
{
trace("Item Clicked")
}
import mx.controls.Alert;
[Bindable]
private var cm:ContextMenu;
override protected function createChildren():void
{
cm = new ContextMenu();
cm.hideBuiltInItems();
cm.addEventListener(ContextMenuEvent.MENU_SELECT, contextMenu_menuSelect);
this.contextMenu = cm;
}
private function contextMenu_menuSelect(evt:ContextMenuEvent):void {
//condition to check length of column data length
var allNull:Boolean=true;
var columnName:String = DataGridColumn(data).headerText;
for each(var o:Object in DataGrid(owner).dataProvider) {
if(o[columnName] != "") {
allNull=false;
break;
}
}
if(!allNull)
{
var cmi:ContextMenuItem = new ContextMenuItem("First Element...", true);
cmi.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, contextMenuItem_menuItemSelect);
cm.customItems = [cmi];
}
}
private function contextMenuItem_menuItemSelect(evt:ContextMenuEvent):void {
}
]]>
</fx:Script>
</mx:Label>

Flex: update datagrid dataProvider cause the datagrid's visible property to be set to to TRUE

I notice this behavior on the Flex 4's datagrid, where I set the gird's visible to FALSE. As I update the grid's dataProvider data, for example update an entity's property in the collection, the grid will become VISIBLE again.
is this the default behavior of a datagird in Flex? How do i disable it?
I've just coded a quick sample :
<?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" minWidth="955" minHeight="600"
creationComplete="application1_creationCompleteHandler(event)"
>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
[Bindable]
public var myData:ArrayCollection = new ArrayCollection;
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
var u:User;
for (var i:int=0; i < 5; i++)
{
u = new User();
u.name = "custom "+int(Math.random()*10);
u.phone = "0987 "+int(Math.random()*10);
myData.addItem(u);
}
}
protected function button1_clickHandler(event:MouseEvent):void
{
myData.getItemAt(0).name = "test";
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout />
</s:layout>
<mx:DataGrid dataProvider="{myData}" visible="false">
<mx:columns>
<mx:DataGridColumn dataField="name" />
<mx:DataGridColumn dataField="phone" />
</mx:columns>
</mx:DataGrid>
<s:Button label="Change data" click="button1_clickHandler(event)" />
</s:Application>
And the DataGrid visibility is not changed so there is obviously something wrong in your code.
Could you post some of your code?

Problem linking datagrid to text Input

What I am trying to do is have a user input his data into multiple textboxes, then once the data is entered it is displayed on the datagrid at runtime. The problem is when I run the app I click my button but no information entered is added to datagrid. My textboxes are also supposed to clear once the button is pressed but again nothing happens. Here is my code:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]private var dgItems:ArrayCollection;
[Bindable]public var temp:Object;
public function addItem(evt:Event):void {
//add item if the text input fields are not empty
if(name_input.text != ""&& location_input.text !="") {
//create a temporary Object
temp = myDG.selectedItem;
var temp:Object = new Object();
//add the text from the textfields to the object
temp = {name:name_input.text, location:location_input.text};
//this will add the object to the ArrayColldection (wich is binded with the DataGrid)
dgItems.addItem(temp);
//clear the input fields
name_input.text = "";
location_input.text ="";
}
}
]]>
</mx:Script>
<mx:DataGrid x="97" y="110" dataProvider="{dgItems}" id="myDG">
<mx:columns>
<mx:DataGridColumn headerText="Column 1" dataField="name:"/>
<mx:DataGridColumn headerText="Column 2" dataField="location:"/>
</mx:columns>
</mx:DataGrid>
<mx:Button x="97" y="51" label="add" click="addItem(event)"/>
<mx:TextInput x="117" y="300" id="location_input"/>
<mx:TextInput x="117" y="340" id="name_input"/>
</mx:Application>
Any help is greatly appreciated.
Your code has lots of errors. First, you were not initializing the dgItems array collection, so it's value was null. You would get errors when you tried to "addItem" to the null object.
Second you were trying to access the selectedItem of the dataGrid before initializing the DataGrid's ArrayCollection dataProvider. No items in the list, there can be no selectedItem.
Third, you're creating the new object twice; once with the 'new Object' line and again with
the in-line syntax for defining ojects: '{}
Fourth, the datafield properties on the DataGridColumn both had colons in them, but the object's properties did not.
I hope this helps.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
// array collection was never initialized; you can't items to a null object
[Bindable]private var dgItems:ArrayCollection = new ArrayCollection();
// not needed
// [Bindable]public var temp:Object;
public function addItem(evt:Event):void {
//add item if the text input fields are not empty
if(name_input.text != ""&& location_input.text !="") {
//create a temporary Object
// this line of code serves no purpos
// temp = myDG.selectedItem;
var temp:Object // = new Object();
//add the text from the textfields to the object
temp = {name:name_input.text, location:location_input.text};
//this will add the object to the ArrayColldection (wich is binded with the DataGrid)
dgItems.addItem(temp);
//clear the input fields
name_input.text = "";
location_input.text ="";
}
}
]]>
</mx:Script>
<mx:DataGrid x="97" y="110" dataProvider="{dgItems}" id="myDG">
<mx:columns>
<!-- need to remove the colons from the data field -->
<mx:DataGridColumn headerText="Column 1" dataField="name"/>
<mx:DataGridColumn headerText="Column 2" dataField="location"/>
</mx:columns>
</mx:DataGrid>
<mx:Button x="97" y="51" label="add" click="addItem(event)"/>
<mx:TextInput x="117" y="300" id="location_input"/>
<mx:TextInput x="117" y="340" id="name_input"/>
</mx:Application>
Many of these errors were easy to catch as soon as I launched the debugger. If you aren't already using it, I suggest doing some reading up on it.

Assigning an array of objects to a DataGrid

When the dataProvider for an DataGrid is an array of objects, how do I set each column's dataField to a property of the object.
I have an ArrayCollection (say a) where each item is an object
For example a[i] = data:Object
Where the object data has some subproperties - data.name, data.title, data.content etc.
I have a DataGrid in which I want to display this data.
So I put:
<mx:DataGrid id="entries" dataProvider="{resultRSS}">
<mx:columns>
<mx:Array>
<mx:DataGridColumn headerText="Title" dataField="data.title"/>
<mx:DataGridColumn headerText="Date" dataField="data.created"/>
</mx:Array>
</mx:columns>
</mx:DataGrid>
This doesn't seem to work at all. I get an empty DataGrid. How should I assign the dataField property, so that it shows up properly? I've tried {data.title} too.
Thanks.
Edit: sample of my data
-[]arraycollection
--[0]
----id="id1"
----data.
------title="something"
------name="something"
------text="some html"
--[1]
----id="id2"
----data.
------title="something2"
------name="something2"
------text="some html2"
and table should be
|title |name |text |
=================================
|something |something |some html|
|something2|something2|somehtml2|
here is your answer
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="initialize()">
<mx:Script>
<![CDATA[
import mx.collections.HierarchicalData;
var a:Array = new Array();
var o:Object = {};
private function initialize():void{
o["text"]="hello";
o["desc"]="Rahul";
a.push(o);
}
]]>
</mx:Script>
<mx:AdvancedDataGrid width="100%" height="100%" sortExpertMode="true" id="adg1" designViewDataType="tree" dataProvider="{new HierarchicalData(a)}">
<mx:columns>
<mx:AdvancedDataGridColumn headerText="text" dataField="text"/>
<mx:AdvancedDataGridColumn headerText="desc" dataField="desc"/>
</mx:columns>
</mx:AdvancedDataGrid>
</mx:Application>
edit - ok now discard my previous answer according to your data try this
var a:Array = new Array();
var o:Object = {};
private function stringArrayToObjectArray():void{
o["id"]="mauj";
var oj:Object=new Object();
oj["title"]="aaa";
o["data"]=oj;
var oj1:Object=new Object();
oj1["id"]="mauj2";
var oj2:Object=new Object();
oj2["title"]="qqqq";
oj1["data"]=oj2;
a.push(o);
a.push(oj1);
}
private function some_labelFunc(item:Object,th:Object):String {
return item.data.title;
}
]]>
</mx:Script>
<mx:AdvancedDataGrid width="100%" height="100%" sortExpertMode="true" id="adg1" dataProvider="{a}">
<mx:columns>
<mx:AdvancedDataGridColumn headerText="COMPANIES" dataField="data" labelFunction="some_labelFunc"/>
</mx:columns>
</mx:AdvancedDataGrid>
</mx:Application>
try this sorry for such a bad code

Flex CheckBox in Datagrid

In the followin flex Code :
Also viewable at : http://www.cse.epicenterlabs.com/checkBoxDg/checkBoxDg.html
1. Add a row in datagrid by clicking on "AddRow"
2. Click on "CheckDg" to see the values of all the checkboxes
- it shows "checkBox57" or "checkBox64" or some similar string
3. Now, "select" the checkBox in the first row.
4. Click again on "CheckDg"
-it show "true"
So, initially dp.getItemAt(i).date returns a CheckBox
and later it returns the "selected" value of the CheckBox?
Why this difference?
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" viewSourceURL="srcview/index.html">
<mx:Canvas>
<mx:DataGrid x="69" y="119" id="dgFee" editable="true" dataProvider="{dp}">
<mx:columns>
<mx:DataGridColumn headerText="Date" dataField="date" width="100" editable="true"
editorDataField="selected" rendererIsEditor="true">
<mx:itemRenderer>
<mx:Component>
<mx:CheckBox selected="false">
</mx:CheckBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn dataField="amount" headerText="Amount" editable="true">
<mx:itemEditor>
<mx:Component>
<mx:TextInput restrict="0-9"/>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
<mx:CheckBox x="130" y="54" label="Checkbox" selected="true" click="Alert.show(abc.selected.toString())" id="abc"/>
<mx:Script>
<![CDATA[
import mx.controls.CheckBox;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
public var dp:ArrayCollection = new ArrayCollection();
public function addRow():void
{
var tmp:Object = new Object();
tmp['amount'] = 100;
tmp['date'] = new CheckBox();
dp.addItem(tmp);
}
public function delRow():void
{
if(dgFee.selectedIndex != -1)
dp.removeItemAt(dgFee.selectedIndex);
}
public function loop1():void
{
for(var i:int=0;i<dp.length;i++)
{
Alert.show(dp.getItemAt(i).date);
}
}
]]>
</mx:Script>
<mx:Button x="29" y="89" label="AddRow" click="addRow()"/>
<mx:Button x="107" y="89" label="DelRow" click="delRow()"/>
<mx:Button x="184" y="89" label="CheckDg" click="loop1()"/>
</mx:Canvas>
</mx:Application>
You are not supposed to assign objects to data variables but data. Checkbox.select property is set to your check box object first and then true or false after the preceding actions. Try this instead
public function addRow():void
{
var tmp:Object = new Object();
tmp['amount'] = 100;
tmp['date'] = false; // not new CheckBox();
dp.addItem(tmp);
}
PS: Also dp should be attributed with [Bindable] :-)
When you click on the check box in the grid, it writes "true" or "false" into the date field, replacing the original CheckBox object that was there. I believe what itemEditors (you are using your render as an editor) do is they write the .data property from the respective components into the collection.
Set the 'editable' property for that particular datagrid column as false. This will resolve the issue

Resources