DataGrid ItemRenderer Error
I am populating 3 columns of my datagrid using a simple XML file. The last column is supposed to be an itemrenderer, basically a Button. However the button should appear only on certain rows of the 3rd column of the datagrid depending on the value from the XML file, which is either "true" or "false". So basically I want to set the Visible property of the button in the itemrenderer to true or false.
Here is the whole application
<?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" pageTitle="Dynamic Data Grid">
<!-- <s:layout>
<s:VerticalLayout horizontalAlign="center"/>
</s:layout>-->
<fx:Declarations>
<s:ArrayList id="cccb_dp">
<fx:String>User1</fx:String>
<fx:String>User2</fx:String>
<fx:String>User3</fx:String>
</s:ArrayList>
<fx:XML id="tempXML" source="assets/fieldsXML.xml"/>
<s:XMLListCollection id="fieldsXMLList" source="{tempXML.worker}"/>
</fx:Declarations>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:VGroup verticalAlign="middle" horizontalCenter="1" verticalCenter="1" horizontalAlign="center">
<s:HGroup horizontalAlign="center" verticalCenter="-221" width="580" height="158" x="75">
<s:Label text="CC" width="23" height="24" verticalAlign="middle" fontWeight="bold"/>
<s:DropDownList id="cc_cb" dataProvider="{cccb_dp}" width="175"/>
</s:HGroup>
<mx:DataGrid id="myDG" dataProvider="{fieldsXMLList}">
<mx:columns>
<mx:DataGridColumn headerText="Header1" dataField="@field_label"/>
<mx:DataGridColumn headerText="Header2" dataField="@field_value"/>
<mx:DataGridColumn headerText="Header3">
<mx:itemRenderer>
<fx:Component>
<s:Button click="onClick(event)" label="Click Me" dataChange="onDataChange(event)" >
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function onClick(evt:Event):void
{
Alert.show(data.@field_visibi开发者_运维技巧lity);
}
private function onDataChange(evt:Event):void
{
visible=data.@field_visibility;
}
]]>
</fx:Script>
</s:Button>
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</s:VGroup>
</s:Application>
The XML:
<worker_fields>
<worker id="1" field_label="Seller" field_value="5" field_visibility="false"/>
<worker id="1" field_label="Balance" field_value="100" field_visibility="true"/>
<worker id="1" field_label="Cash Owned" field_value="300" field_visibility="true"/>
<worker id="2" field_label="Seller" field_value="5" field_visibility="false"/>
<worker id="2" field_label="Balance" field_value="130" field_visibility="true"/>
<worker id="2" field_label="Cash Owned" field_value="132" field_visibility="false"/>
<worker id="2" field_label="Credits" field_value="131" field_visibility="true"/>
</worker_fields>
Any idea how to go around it.
Thanks you for the precious help.
Each itemRenderer gets a data object; which contains the element the renderer is displaying. There is not going to be a property named field_visibility in your renderer because it is not a default property and you didn't create one.
However, it should be a property on the data object passed into the renderer.
The data property should point to a single worker:
<worker id="1" field_label="Cash Owned" field_value="300" field_visibility="true"/>
And you should be able to access it with slight mods to your code:
<mx:itemRenderer>
<fx:Component>
<mx:Button click="onClick(event)" label="Click Me" visible="{data.@field_visibility}">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function onClick(evt:Event):void
{
Alert.show(data.field_visibility);
}
]]>
</fx:Script>
</mx:Button>
</fx:Component>
</mx:itemRenderer>
For best results; you should consider listening to the data change event and changing the visibility in that way. This is known to cause less issues, long term, than the use of binding:
<mx:itemRenderer>
<fx:Component>
<mx:Button click="onClick(event)" label="Click Me" dataChange="onDataChange()" >
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function onClick(evt:Event):void
{
Alert.show(data.field_visibility);
}
private function onDataChange(evt:Event):void
{
visible=data.@field_visibility";
}
]]>
</fx:Script>
</mx:Button>
</fx:Component>
</mx:itemRenderer>
For some reason the original posters last code edit wiped out his actual question. Flex is having an issue translating the the XML string value into a Boolean value. data.@field_visibility
appears to be returning an XMLList. As a Boolean value that will always be true. That is issue one. It can be solved by doing a conditional like this:
if(data.@field_visibility == "true"){
this.button.visible = true;
} else {
this.button.visible = false;
}
The second issue is that the button doesn't appear to vanish if it is the top level component. So, you need to place it inside a container. I used a Canvas.
Here is modified application:
<?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" pageTitle="Dynamic Data Grid">
<!-- <s:layout>
<s:VerticalLayout horizontalAlign="center"/>
</s:layout>-->
<fx:Declarations>
<s:ArrayList id="cccb_dp">
<fx:String>User1</fx:String>
<fx:String>User2</fx:String>
<fx:String>User3</fx:String>
</s:ArrayList>
<fx:XML id="tempXML" source="assets/fieldsXML.xml"/>
<s:XMLListCollection id="fieldsXMLList" source="{tempXML.worker}"/>
</fx:Declarations>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:VGroup verticalAlign="middle" horizontalCenter="1" verticalCenter="1" horizontalAlign="center">
<s:Button click="{myDG.invalidateList()}" label="Invalidate List" />
<s:HGroup horizontalAlign="center" verticalCenter="-221" width="580" height="158" x="75">
<s:Label text="CC" width="23" height="24" verticalAlign="middle" fontWeight="bold"/>
<s:DropDownList id="cc_cb" dataProvider="{cccb_dp}" width="175"/>
</s:HGroup>
<mx:DataGrid id="myDG" dataProvider="{fieldsXMLList}">
<mx:columns>
<mx:DataGridColumn headerText="Header1" dataField="@field_label"/>
<mx:DataGridColumn headerText="Header2" dataField="@field_value"/>
<mx:DataGridColumn headerText="Header3">
<mx:itemRenderer>
<fx:Component>
<mx:Canvas dataChange="container1_dataChangeHandler(event)" >
<mx:Button label="Click Me" id="button" />
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function container1_dataChangeHandler(event:FlexEvent):void
{
if(data.@field_visibility == "true"){
this.button.visible = true;
} else {
this.button.visible = false;
}
}
]]>
</fx:Script>
</mx:Canvas>
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</s:VGroup>
</s:Application>
In addition to @www.Flextras.com's answer.
If you want to rely on your column's dataField
property and make your renderer data agnostic, you can implement mx.controls.listClasses.IDropInListItemRenderer
interface in your renderer. As far as you inherited from MX Button
which already implemented it the code will be the following:
<mx:DataGrid dataProvider="{fieldsXMLList}" id="myDG">
<mx:columns>
<mx:DataGridColumn dataField="@field_label" headerText="Header1" />
<mx:DataGridColumn dataField="@field_value" headerText="Header2" />
<mx:DataGridColumn dataField="@field_visibility" headerText="Header3">
<mx:itemRenderer>
<fx:Component>
<mx:Button click="onClick(event)" label="Click Me" visible="{data[listData.dataField]}">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function onClick(evt:Event):void
{
Alert.show(data[listData.dataField]);
}
]]>
</fx:Script>
</mx:Button>
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
精彩评论