Getting flex datagrid cell value using column and row indices - apache-flex

i'm using flex for an application but i'm having some trouble to recover data from a datagrid that has a checkbox in one of the columns, the problem is that i can't use the function selectedIndex or selectedItem, because they are used to save the checked items.
Is there a way to recovery the datagrid informations using the column and row indices? Something like:
MyDataGrid[row][column] or MyDataProvider[row][column] or any combination of functions to allow me recovery an information using only the row and column.
Thanks

If you just want to be able to get a cell value of the data grid using row and col indices, you can extend the DataGrid component and add one simple function.
Here is a working example.
It looks something like this:
//CustomDataGrid
<?xml version="1.0" encoding="utf-8"?>
<s:DataGrid xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="400" height="300">
<fx:Script>
<![CDATA[
import spark.components.gridClasses.GridColumn;
public function getElementAt(row:int, col:int):Object
{
if (this.dataProvider.length < row + 1 || this.columns.length < col + 1)
return null;
else
return this.dataProvider.getItemAt(row)[(this.columns.getItemAt(col) as GridColumn).dataField];
}
]]>
</fx:Script>
</s:DataGrid>
Then you call it in your application like this:
//App
<?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"
xmlns:dgrc="com.dgrc.*">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
[Bindable]private var collection:ArrayCollection = new ArrayCollection([
{fld01:1, fld02:"fld02", fld03:"fld13", fld04:"fld14"},
{fld01:2, fld02:"fld02", fld03:"fld23", fld04:"fld24"},
{fld01:3, fld02:"fld02", fld03:"fld33", fld04:"fld34"},
{fld01:4, fld02:"fld02", fld03:"fld43", fld04:"fld44"},
{fld01:5, fld02:"fld02", fld03:"fld53", fld04:"fld54"}
]);
protected function getElement():void
{
var obj:Object = myDG.getElementAt(nsRow.value, nsCol.value);
Alert.show(String(obj));
}
]]>
</fx:Script>
<s:VGroup x="20" y="20">
<s:HGroup>
<s:NumericStepper id="nsRow" minimum="0" value="0"/>
<s:NumericStepper id="nsCol" minimum="0" value="0"/>
<s:Button label="Get It!" click="getElement()"/>
</s:HGroup>
<dgrc:CustomDataGrid id="myDG" width="300" height="160" dataProvider="{collection}">
<dgrc:columns>
<s:ArrayList>
<s:GridColumn dataField="fld01" headerText="Field 1" width="100"/>
<s:GridColumn dataField="fld03" headerText="Field 3" width="100"/>
<s:GridColumn dataField="fld04" headerText="Field 4"/>
</s:ArrayList>
</dgrc:columns>
</dgrc:CustomDataGrid>
</s:VGroup>
</s:Application>
Be aware that the row and col indices in this example refer a cell of the data grid and not a value of the data grid provider.
If you call
getElementAt(0, 1)
you will get "fld13"

If you are using the original DataGrid control, it is better to use the itemToLabel method of DataGridColumn, because item[dataField] will cause an exception when the property value contains dot notation, such as "customer.name":
public function getElementAt(row:int, col:int):Object {
var item:Object = dataProvider.getItemAt(row)
var column:DataGridColumn = dataGrid.columns[column] as DataGridColumn;
var value:String = column.itemToLabel(item);
return value;
}
This same method is used by the framework to provide the text displayed in the grid cell. If your checkbox in the grid is driven by a boolean property, the returned value will be true or false.

Related

Flex : How to reuse Item renderer?

I have a data grid table, the gridColumn in the dataGrid table calls a "DropDownListItemRenderer". Using the same item renderer I want to change the contents in the drop down list according to the dataField name. So for example if the dataField name is colour then the drop down will contain red,blue,green ect. If the dataField name is furits, then the drop down list will contain different fruits options.
If u look at the codes in my item Renderer. I tried to do the above by creating a bindable array collection called dropDownListData. In the override set data function I get the dataField name, Using the data field name I add items in array collection accordingly.
Although the dropdown list is filled with the correct data when u run the program. The data in the drop down list is repeated and increased every time when the dropdown list is selected.
I think I am not using the right method to do this. So can someone show me how I do this ? Pls can someone help me with this ? Pls let me know if my question is not clear I will try to rephrase it.
Thanks :)
This is my MXML file :
<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 FrontEndObjects.ColourItems;
import mx.collections.ArrayCollection;
import spark.events.IndexChangeEvent;
[Bindable]
private var order:ArrayCollection = new ArrayCollection();
private function addOrder():void{
var orderItems:ColourItems = new ColourItems();
order.addItem(orderItems);
}
]]>
</fx:Script>
<s:BorderContainer x="175" y="101" width="606" height="289">
<s:DataGrid id="myDG" x="53" y="27" width="516" height="201" dataProvider="{order}"
editable="true" variableRowHeight="true">
<s:columns>
<s:ArrayList>
<s:GridColumn dataField="label1" headerText="Order #" editable="true"/>
<s:GridColumn dataField="quant" headerText="Qty" editable="true"/>
<s:GridColumn dataField="color" headerText="Color" editable="true" rendererIsEditable="true" itemRenderer="myRenderers.DropDownListItemRenderer"/>
<s:GridColumn dataField="furits" headerText="Furits" editable="true" rendererIsEditable="true" itemRenderer="myRenderers.DropDownListItemRenderer"/>
</s:ArrayList>
</s:columns >
</s:DataGrid>
<s:Button x="499" y="236" label="add" click="addOrder()" />
</s:BorderContainer>
This is my DropDownList item Renderer :
<s:GridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" clipAndEnableScrolling="true">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import spark.components.gridClasses.GridColumn;
import spark.events.IndexChangeEvent;
public var cName:String;
[Bindable]
private var dropDownListData:ArrayCollection = new ArrayCollection();
protected function onCbChange(event:IndexChangeEvent):void
{
var value:String = (event.currentTarget as DropDownList).selectedItem;
data[column.dataField] = value;
}
override public function set data(value:Object):void
{
super.data = value;
cName = column.dataField;
if(cName == "color"){
dropDownListData.addItem("red");
dropDownListData.addItem("blue");
dropDownListData.addItem("green");
}
else if(cName == "furits"){
dropDownListData.addItem("banana");
dropDownListData.addItem("apple");
dropDownListData.addItem("grapes");
}
}
]]>
</fx:Script>
<s:DropDownList id="cb" width="100%" change="onCbChange(event)" requireSelection="true" dataProvider="{dropDownListData}"/>
This is my Object class :
public class ColourItems
{
public var label1:String;
public var quant:String;
public var color:String;
public var furits:String;
}
In the setData method of the itemRenderer, you should check what data already exists in the list before doing the addItem
You set target columns as editable: editable="true" rendererIsEditable="true". When you click for cell, grid calls set data(value:Object) method in itemrenderer where you add items in dropdown list more more and more. You can easy fix it as disabled editable for cell:
<s:GridColumn dataField="color" headerText="Color" editable="false" itemRenderer="myRenderers.DropDownListItemRenderer"/>
<s:GridColumn dataField="furits" headerText="Furits" editable="false" itemRenderer="myRenderers.DropDownListItemRenderer"/>

Flex DataGrid does not sort correctly if a column contains custom UIComponent

I have a DataGrid with the first column being strings ("Red", "Blue", etc) and the second column being a circle (custom UIComponent) of the corresponding color. If I click on the first column to sort, all the names of the colors are sorted fine but those circles in the second column are in totally wrong order. Anyone knows what went wrong with the code below?
This is the application mxml:
<?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"
xmlns:components="components.*"
minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var myArray:ArrayCollection = new ArrayCollection([
{ name:"Red", color:0xff0000 },
{ name:"Orange", color:0xff8000 },
{ name:"Yellow", color:0xffff00 },
{ name:"Green", color:0x00ff00 },
{ name:"Blue", color:0x0000ff },
{ name:"Purple", color:0xff00ff }
]);
]]>
</fx:Script>
<s:DataGrid dataProvider="{myArray}">
<s:columns>
<s:ArrayCollection>
<s:GridColumn dataField="name"/>
<s:GridColumn dataField="color">
<s:itemRenderer>
<fx:Component>
<s:GridItemRenderer>
<s:VGroup>
<components:Circle color="{data.color}" />
</s:VGroup>
</s:GridItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:GridColumn>
</s:ArrayCollection>
</s:columns>
</s:DataGrid>
</s:Application>
And this is the custom UIComponent:
package components
{
import mx.core.UIComponent;
public class Circle extends UIComponent
{
public var color:uint;
public function Circle()
{
super();
height = 20;
width = 20;
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledWidth);
graphics.clear();
graphics.beginFill(color, 1);
graphics.drawCircle(10, 10, 8);
graphics.endFill();
}
}
}
Your custom component is probably simply not redrawn. The easiest solution to this is to not use a custom component at all and use FXG graphics to draw your circle instead.
Replace your itemrenderer with this one and it should work fine:
<s:GridItemRenderer>
<s:Ellipse width="20" height="20">
<s:fill>
<s:SolidColor color="{data.color}" />
</s:fill>
</s:Ellipse>
</s:GridItemRenderer>
That said, I would put the label and the color sample in one column (instead of two) since they represent the same data.

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 Spark datagrid - disable selection of a row

I want to disable (and look disabled) some rows in a spark datagrid. I found this answer to stop selection which is great
In flex, is there a way to capture and optionally cancel a row selection event in a DataGrid?
But I want in addition to show that the particular row is not selectable. Ideally I want to have some sort of overlay but I am not sure if that is possible. My alternative solution is to change the text color to grey for the unselectable row. Looking at the datagrid renders they all seem to be column based. I looked at skinning potentially (overriding the alternating color property) but this just sets the background property and not the text color. Is this possible?
Thanks
The most basic solution is using the custom renderer and selection preventing logic you've mentioned:
DataGridRowDisabling.mxml
<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" xmlns:local="*">
<fx:Script>
<![CDATA[
import spark.events.GridSelectionEvent;
private function dataGrid_selectionChangingHandler(event:GridSelectionEvent):void
{
var index:int = event.selectionChange.rowIndex;
var product:Product = dataGrid.dataProvider.getItemAt(index) as Product;
if (product && !product.enabled)
event.preventDefault();
}
]]>
</fx:Script>
<s:DataGrid id="dataGrid" itemRenderer="GridItemRenderer2" selectionChanging="dataGrid_selectionChangingHandler(event)">
<s:dataProvider>
<s:ArrayCollection>
<local:Product name="iPod" price="199.99"/>
<local:Product name="iPad 3" price="499.99"/>
<local:Product name="iPad 4" price="599.99" enabled="false"/>
<local:Product name="iPad 5" price="699.99" enabled="false"/>
</s:ArrayCollection>
</s:dataProvider>
</s:DataGrid>
</s:Application>
GridItemRenderer2.mxml
<s:GridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" clipAndEnableScrolling="true">
<fx:Script>
<![CDATA[
override public function prepare(hasBeenRecycled:Boolean):void
{
if (data is Product)
enabled = Product(data).enabled;
lblData.text = data[column.dataField];
}
]]>
</fx:Script>
<s:Label id="lblData" top="9" left="7"/>
</s:GridItemRenderer>
Product.as
package
{
public class Product
{
public var name:String;
public var price:Number;
public var enabled:Boolean = true;
}
}

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?

Resources