Flex : How to reuse Item renderer? - apache-flex

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"/>

Related

Displaying a checkbox column in a Flex DataGrid

I am trying to create a custom Flex DataGrid which consists of two columns, one for label and the other for a checkbox.
The checkbox is contained within a class called CustomRenderer that inherits from GridItemRenderer and implements IFactory.
In each instance of CustomRenderer, I have a variable called number so that when a checkbox is clicked, it can pass back the number so that I know which row has been clicked.
The problem is that my CustomRenderer does not show when the program runs.
Please could someone help.
Here is my code.
MyProgram.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" minWidth="955" minHeight="600"
initialize="initData()">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.controls.CheckBox;
import mx.rpc.events.AbstractEvent;
private var ArrayItems:Array = [
{Label:'Table'},
{Label:'Chair'},
{Label:'Stool'},
{Label:'Bench'},
{Label:'Sofa'}];
[Bindable]
private var ArrayCollectionItems:ArrayCollection;
private var t:CustomRenderer;
public function initData():void
{
ArrayCollectionItems=new ArrayCollection(ArrayItems);
t = new CustomRenderer();
t.cb.addEventListener(MouseEvent.CLICK, HandleClick);
MainGrid.columns[1].itemRenderer = t.newInstance();
}
public function HandleClick(event:Event):void
{
var c:CustomRenderer = (event.currentTarget) as CustomRenderer
var RowClicked:int = c.number;
}
]]>
</fx:Script>
<s:states>
<s:State name="State1"/>
</s:states>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Panel x="99" y="14" width="379" height="268" skinClass="spark.skins.spark.PanelSkin">
<s:DataGrid id="MainGrid" x="19" y="17" width="340" height="199"
dataProvider="{ArrayCollectionItems}" requestedRowCount="4" requireSelection="false"
resizableColumns="false" selectionMode="singleRow" showDataTips="false">
<s:columns>
<s:ArrayList>
<s:GridColumn minWidth="200" dataField="Label" headerText="Label"></s:GridColumn>
<s:GridColumn minWidth="30" dataField="" headerText="">
</s:GridColumn>
</s:ArrayList>
</s:columns>
<s:typicalItem>
<fx:Object dataField1="Sample Data" dataField2="Sample Data" dataField3="Sample Data"></fx:Object>
</s:typicalItem>
</s:DataGrid>
</s:Panel>
</s:Application>
CustomRenderer.as
import mx.controls.Alert;
import mx.controls.CheckBox;
import mx.core.IFactory;
import spark.components.gridClasses.GridItemRenderer;
public class CustomRenderer extends GridItemRenderer implements IFactory
{
private static var count:int = 0;
public var number:int;
public var cb:CheckBox;
public function CustomRenderer()
{
cb = new CheckBox();
number = count++;
cb.x = 22;
cb.y = 4;
addElement(cb);
}
public function newInstance():*
{
return new CustomRenderer();
}
}
Probably that's because you pass an instance of the itemrenderer to the column (new CustomRenderer()) instead of a class (CustomRenderer). The common approach is to pass the itemrenderer class to your column and then handle the clicks / selection inside of it:
<s:GridColumn minWidth="30" headerText="" itemRenderer="com.yourpackage.CustomRenderer">
Just start typing "Customrenderer" when you assign it and you should be able to autocomplete so it writes out your full package path.
Then you catch the checkbox select events inside of the renderer and could set some custom data property (for example, data.selected). If you really need to do something outside of your Grid after the selection you might need to fire a custom event from your renderer on selection and listen for it on your datagrid.

Getting flex datagrid cell value using column and row indices

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.

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 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