ActionScript Item Renderer in DataGrid - actionscript-3

I am using this example from blog.flexexamples.com.
I have a datagrid and trying to dynamically add button to one of datagrid column. But I want this Button as an ItemRenderer to be written in ActionScript and not MXML.
How can I do that ?
Thanks

I think this is what you need.
ActionButtonItemRenderer.as :
package
{
import flash.events.MouseEvent;
import mx.controls.Alert;
import mx.controls.Button;
import mx.controls.listClasses.IDropInListItemRenderer;
import mx.controls.listClasses.IListItemRenderer;
import mx.core.IFlexDisplayObject;
public class ActionButtonItemRenderer extends Button implements IFlexDisplayObject, IListItemRenderer, IDropInListItemRenderer
{
public var btn:Button;
public function ActionButtonItemRenderer()
{
super();
btn = new Button();
btn.label = "Take Action";
btn.addEventListener(MouseEvent.CLICK,clickHandler);
btn.visible = btn.includeInLayout = true;
}
override protected function clickHandler(event:MouseEvent):void
{
super.clickHandler(event);
Alert.show("Button clicked");
}
}
}
DynamicDataGridButton.mxml :
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600">
<mx:ApplicationControlBar dock="true">
<mx:Button label="Add column" click="init();" />
</mx:ApplicationControlBar>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var arr:ArrayCollection = new ArrayCollection
(
[
{fname:'A',lname:'B'},
{fname:'C',lname:'B'},
{fname:'D',lname:'B'}
]
);
private function addDataGridColumn(dataField:String):void {
var dgc:DataGridColumn = new DataGridColumn(dataField);
dgc.itemRenderer = new ClassFactory(ActionButtonItemRenderer);
var cols:Array = dg.columns;
cols.push(dgc);
dg.columns = cols;
}
private function init():void {
addDataGridColumn("Details");
}
]]>
</mx:Script>
<mx:DataGrid id="dg" dataProvider="{arr}">
<mx:columns>
<mx:DataGridColumn id="dgc1" dataField="fname" headerText="First Name"
width="75"/>
<mx:DataGridColumn id="dgc2" dataField="lname" headerText=" Last Name"
width="150"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>

To dynamically create a button in AS3 syntax you would do this:
var button:Button = new Button();
Then after you've created the button, you can set it's properties like this:
button.label = "Click Me!";
And lastly you would add it to one of your items as such:
var dp:Array = [{label: "Button 1", button: button},{label: "Button 2", button: button}];
myDg.dataProvider = dp;
Then you would feed it to your datagrid that is laid out like this:
<mx:DataGrid id="myDG" variableRowHeight="true">
<mx:columns>
<mx:DataGridColumn dataField="label" headerText="Labels"/>
<mx:DataGridColumn dataField="button" headerText="Buttons"/>
</mx:columns>
</mx:DataGrid>
Not sure if that would actually work though, you may have to have an button itemRenderer on the entire column like this example.

Related

DataGrid Image ItemRenderer --> How to change image source of other rows, not only the selected one

I have an Image in my DataGrid. Its purpose is to play and stop an audio, so I need to change the image source from the "Play" image to the "Stop" image every time I click on it.
I've already accomplished that with the next code:
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" title="Audio List"
horizontalScrollPolicy="off" verticalScrollPolicy="auto"
showCloseButton="true" close="closeWindow()">
<mx:Script>
<![CDATA[
import flash.external.ExternalInterface;
import mx.collections.ArrayCollection;
import mx.managers.PopUpManager;
public var dpc:ArrayCollection;
private function closeWindow(){
PopUpManager.removePopUp(this);
ExternalInterface.call("pauseAudio");
}
]]>
</mx:Script>
<mx:Rotate id="rotate" />
<mx:Zoom id="zoom" />
<mx:VBox width="100%" top="20">
<mx:Text fontWeight="bold" top="20" left="20">
<mx:text>Click the play/pause button for listening/pause each audio individually:</mx:text>
</mx:Text>
<mx:DataGrid id="gridAudios" top="60" bottom="0" left="0" width="100%" height="100%" doubleClickEnabled="true">
<mx:columns>
<mx:DataGridColumn headerText="Name" dataField="audioId"/>
<mx:DataGridColumn id="btnCol" dataField="url" headerText="" textAlign="center">
<mx:itemRenderer>
<mx:Component>
<mx:HBox>
<mx:Image click="changeImg(data.url)" toolTip="Play"
id="imgPlayStop" useHandCursor="true"/>
<mx:Script>
<![CDATA[
import mx.states.State;
import mx.collections.ArrayCollection;
[Embed(source='../assets/play-btn-small.png')]
[Bindable]
public var Play:Class;
[Embed(source='../assets/stop-btn-small.png')]
[Bindable]
public var Stop:Class;
private function init():void
{
imgPlayStop.source = Play
var statePlaying:State = new State();
var stateStopped:State = new State();
statePlaying.name="playing";
stateStopped.name="stopped";
var states:Array = new Array();
states.push(statePlaying);
states.push(stateStopped);
imgPlayStop.states = states;
imgPlayStop.currentState = "stopped";
}
private function changeImg(url:String):void{
if (imgPlayStop.currentState == "stopped"){
imgPlayStop.source = Stop;
imgPlayStop.currentState = "playing";
ExternalInterface.call("playAudio", url);
} else {
imgPlayStop.source = Play;
imgPlayStop.currentState = "stopped";
ExternalInterface.call("pauseAudio");
}
}
]]>
</mx:Script>
</mx:HBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
</mx:TitleWindow>
But the thing is that I want to change the image source of the other rows of the DataGridColumn.
For example, if I click in the play image of one row it changes to the stop image, everything OK till here.
If now I click the play image of other row, it also changes to the stop image, but the previous row still remains with the stop image, and I want to be only one stope image active.
In other words, I want to give the impression only one audio is playing. So only one of the rows can be with the "Stop" image while the rest must be with the "Play" image.
So, ¿how can I loop through the DataGridColumn items renderer and change their image source every time I click in on of the items renderer?
You can save prev imgPlayStop as public static variable in a Model class and use it
public class Model {
public static var prevImgPlayStop:Image;
}
in your itemRenderer do like this
private function changeImg(url:String):void{
if (Model.prevImgPlayStop) {
Model.prevImgPlayStop.currentState = "stopped";
}
/*your code*/
Model.prevImgPlayStop = imgPlayStop;
}
I post the SOLUTION I founded to my problem:
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" title="Audio List"
horizontalScrollPolicy="off" verticalScrollPolicy="auto" width="510" height="340"
showCloseButton="true" close="closeWindow()">
<mx:Script>
<![CDATA[
import flash.external.ExternalInterface;
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
import mx.controls.Alert;
[Embed(source='../assets/play-btn-small.png')]
var Play:Class;
[Embed(source='../assets/stop-btn-small.png')]
var Stop:Class;
[Blindable]
public var dpc:ArrayCollection;
private function titlewindow1_initializeHandler(event)
{
ExternalInterface.addCallback('onFinishAudio', onFinishAudio);
ExternalInterface.addCallback('onStartAudio', onStartAudio);
}
private function closeWindow(){
PopUpManager.removePopUp(this);
ExternalInterface.call("pauseAudio");
}
private function onFinishAudio(audioId:String) {
for ( var audio:Object in dpc )
{
if (audio.audioId == audioId){
audio.status = 'stopped';
}
}
gridAudios.dataProvider = dpc;
dpc.refresh();
}
private function onStartAudio(audioId:String)
{
for ( var audio:Object in dpc )
{
if (audio.audioId != audioId)
{
if (audio.status == 'playing')
{
audio.status='stopped';
}
} else {
//Alert.show("Dgsg","Error");
audio.status='playing';
}
}
gridAudios.dataProvider = dpc;
dpc.refresh();
}
public function playAudio(audioURL:String, audioId:String){
ExternalInterface.call("playAudio", audioURL, id);
}
public function pauseAudio(){
ExternalInterface.call("pauseAudio");
}
]]>
</mx:Script>
<mx:Rotate id="rotate" />
<mx:Zoom id="zoom" />
<mx:VBox top="0" bottom="0" left="0" right="0" paddingTop="20" paddingLeft="20">
<mx:Text fontWeight="bold" height="20">
<mx:text>Click the play/pause button for listening/pause each audio individually:</mx:text>
</mx:Text>
</mx:VBox>
<mx:DataGrid id="gridAudios" top="50" bottom="20" left="20" right="20" width="100%" doubleClickEnabled="false">
<mx:columns>
<mx:DataGridColumn headerText="Name" dataField="audioId"/>
<mx:DataGridColumn id="btnCol" headerText="" textAlign="center">
<mx:itemRenderer>
<mx:Component>
<mx:HBox horizontalAlign="center">
<mx:Script>
<![CDATA[
protected function image1_clickHandler(event:MouseEvent):void
{
if (data.status=='playing'){
outerDocument.pauseAudio();
data.status='';
}else{
outerDocument.playAudio(data.url,data.audioId);
data.status='playing';
}
}
]]>
</mx:Script>
<mx:Image click="image1_clickHandler(event)"
toolTip="{data.status=='playing' ? 'Stop' : 'Play'}"
useHandCursor="true" source="{data.status=='playing' ? outerDocument.Stop : outerDocument.Play}"/>
</mx:HBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</mx:TitleWindow>
Where the key to the solution is in the source property of the Image object and in the click handler.

How to Access buttons and labels of one mxml file from another mxml file

I m completely fresher in Flex Programming,
I have a FileUploadPanel.mxml which contains functionality of uploading, deleting and viewing one file only.. Now i need to modify the application to accommodate multiple attachments facility, So i created another panel ie MultiFileUpload.mxml, which has the functionality to get all attachment in form of List of Objects , and for each object-id I need to call the previous File Upload Panel, Every Thing is Working fine, but when i am accessing buttons and Labels of FileUpload.mxml it is throwing error:
1009- cannot access property and method of null object reference.
code FileUploadPanel.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="492" height="46" >
<mx:Label x="0" y="4" text="File Attachment:"/>
<mx:Button x="93.5" y="2" label="Browse" id="btnBrowseView" click="__onBrowse();" enabled="true" width="67"/>
<mx:Text x="264.5" y="4" width="100%" id="lbUploadFile" height="18 " />
<mx:Button x="165" y="2" label="Upload" id="btnUpload" enabled="true" click="reserveAttachment();" width="67"/>
<mx:Text x="10" y="25" width="100%" height="18" id="__status__" fontWeight="bold" color="#023AF1"/>
<mx:Script>
<![CDATA[
public function SetAttachmentID(anAttachmentID: Number): void
{
this.AttachmentID = anAttachmentID;
lbUploadFile.text = ""; //here i am getting error
__status__.text = "";
if (AttachmentID != -1)
{
m_data = new DocumentsAdt();
m_data.ConnectionIndex = ConnectionIndex;
m_data.OnLoadData = this.OnDoxLoaded;
m_data.LoadFromWebService(AttachmentID);
btnBrowseView.label = "View";
btnUpload.label = "Delete";
btnUpload.enabled = true;
btnUpload.visible = true;
}
else
{
btnBrowseView.label = "Browse";
btnUpload.visible = false;
btnUpload.label = "Upload";
btnUpload.enabled = false;
Init();
}
}
</mx:Script>
</mx:Canvas>
Code MuliFileUpload.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300" xmlns:BoycePanels="BoycePanels.*" xmlns:ns1="com.flextoolbox.controls.*" xmlns:ns2="com.adobe.flex.extras.controls.*" xmlns:ns3="BoycePanels.*">
<mx:Script>
<![CDATA[
import Adt.Attachments.DocumentsAdt;
import com.boycepensions.DocumentsService.DocumentsService;
import com.boycepensions.DocumentsService.GetDocumentsRecordResultEvent;
import mx.collections.ArrayCollection;
private var m_data: DocumentsAdt = null;
import mx.rpc.events.FaultEvent;
import BoycePanels.FileUploadPanel;
import mx.controls.Alert;
public var ConnectionIndex: int = new int(0);
public var AttachmentID: Number = new Number(-1);
public var acDocList:ArrayCollection=null;
public function Init():void
{
getDocs_Test();
}
public function getDocs_Test():void
{
blah..blah..blah..
}
public function OnGetDocumentsRecord(event:GetDocumentsRecordResultEvent): void
{
var acDocList:ArrayCollection=new ArrayCollection();
var m_data:DocumentsAdt=new DocumentsAdt();
if (!CheckResult(event.result))
return;
else
{
acDocList=m_data.LoadDocumentsFromXML(event.result);
for each(var obj:DocumentsAdt in acDocList)
{
var pnl:FileUploadPanel=new FileUploadPanel();
//pnl.OnReserveAttachmentDone=OnReserveAttachment;
pnl.Init();
pnl.SetAttachmentID(obj.Document_ID); //here it is throwing error
}
}
}
Please suggest, i have already spent days and hours on it..
You try to access lbUploadFile when it hasn't been initialized. So if you want the FileUploadPanel show on Stage, try add it to stage before call SetAttachmentID function, like this.
var pnl:FileUploadPanel=new FileUploadPanel();
this.addChild(pnl);//add it to where you want
If the pnl needn't show on stage, remove the lines where access the children.

When using TabNavigator how to align content of dynamically added tab

Given a simple example:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import com.example.Tab;
private function addSecondTab(event:Event):void {
tabs.addChild(new Tab("Second"));
}
]]>
</mx:Script>
<mx:TabNavigator id="tabs" width="100%" height="100%">
<mx:VBox horizontalAlign="center" verticalAlign="middle" label="#1">
<mx:Label text="test"/>
</mx:VBox>
</mx:TabNavigator>
<mx:Button label="Add Second Tab" click="addSecondTab(event)" />
</mx:Application>
package com.example {
import mx.containers.VBox;
import mx.controls.Label;
import mx.events.FlexEvent;
public class Tab extends VBox {
public function Tab(name:String) {
label = name;
setStyle("horizontal-align", "center");
setStyle("vertical-align", "middle");
}
override protected function createChildren():void {
super.createChildren();
var box:VBox = new VBox();
box.setStyle("border-style", "solid");
box.setStyle("border-thickness", 1);
box.setStyle("border-color", 0xFF0000);
var l1:Label = new Label();
l1.text = "Hello!";
box.addChild(l1);
var l2:Label = new Label();
l2.setStyle("fontWeight", "bold");
l2.text = "This is a line of text...";
box.addChild(l2);
addChild(box);
}
}
}
Why aren't styles (border and alignment) being applied inside the second tab?
Flex only supports hyphenated style names in CSS. So in MXML or Actionscript statements you should use the camel case versions of the style names:
horizontalAlign, verticalAlign, borderStyle, etc.
You can read more about it in Adobe's documentation, in particular this section on CSS selector names.

Using itemRenderer in mx Datagrid

I have a mx DataGrid with 2 column. The first column has its data rendered in a TextInput and the second column renderer in a ComboBox. When I change the selected value in the ComboBox, I want the TextInput of the same index to have its text changed to the value selected in the ComboBox. Can anyone help me with this? My code is below.
<mx:DataGrid id="myGrid" rowHeight="25" dataProvider="{Testarray}" width="100%" height="205" chromeColor="#D0CCAF" headerHeight="0" showHeaders="false" >
<mx:columns>
<mx:DataGridColumn headerText="My Header 1"
editable="true"
dataField="LBL"
>
<mx:itemRenderer>
<fx:Component>
<mx:HBox horizontalAlign="left" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<s:TextInput id="label_txt" text="{data.LBL}" width="98%"/>
</mx:HBox>
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn headerText="My Header 2"
editable="true"
rendererIsEditor="true"
dataField="ALIAS"
>
<mx:itemRenderer>
<fx:Component>
<renderers:comboItemRenderer height="80%" change="comboitemrenderer1_changeHandler(event)" lookupField="ALIAS" labelField="ALIAS" dataProvider="{outerDocument.searchCustomizationComponents_array}">
<fx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.events.ListEvent;
protected function comboitemrenderer1_changeHandler(event:ListEvent):void
{
//WHAT TO PUT HERE?
}
]]>
</fx:Script>
</renderers:comboItemRenderer>
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
I got it myself. Thanks buddies.
I needed to add these 2 lines of codes for the textInput to take the value of the selectedItem int he ComboBox.
protected function comboitemrenderer1_changeHandler(event:ListEvent):void
{
outerDocument.myGrid.dataProvider[outerDocument.myGrid.selectedIndex]['LBL'] = this.selectedItemKey;
outerDocument.myGrid.invalidateList();
}
Also note that the code for my comboitemrenderer below:
<mx:ComboBox
xmlns:mx="http://www.adobe.com/2006/mxml"
dataChange="setSelected()"
change="onSelectionChange(event)"
focusEnabled="true">
<mx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.events.ListEvent;
import mx.controls.dataGridClasses.DataGridListData;
private var _ownerData:Object;
private var _lookupField:String = "value";
// When using this component as an itemEditor rather than an itemRenderer
// then set ' editorDataField="selectedItemKey"' on the column to
// ensure that changes to the ComboBox are propogated.
[Bindable] public var selectedItemKey:Object;
public function set lookupField (value:String) : void {
if(value) {
_lookupField = value;
setSelected();
}
}
override public function set data (value:Object) : void {
if(value) {
_ownerData = value;
setSelected();
}
}
override public function get data() : Object {
return _ownerData;
}
private function setSelected() : void {
if (dataProvider && _ownerData) {
var col:DataGridListData = DataGridListData(listData);
for each (var dp:Object in dataProvider) {
if (dp[_lookupField] == _ownerData[col.dataField]) {
selectedItem = dp;
selectedItemKey = _ownerData[col.dataField];
return;
}
}
}
selectedItem = null;
}
private function onSelectionChange (e:ListEvent) : void {
if (selectedItem && _ownerData) {
var col:DataGridListData = DataGridListData(listData);
_ownerData[col.dataField] = selectedItem[_lookupField];
selectedItemKey = selectedItem[_lookupField];
}
}
]]>
</mx:Script>
</mx:ComboBox>

ItemRollOver with a custom ToolTip

I have this custom toolTip:
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
implements="mx.core.IToolTip"
creationPolicy="all"
cornerRadius="4" borderStyle="solid" backgroundColor="#FFFFFF"
creationComplete="init()" width="100" height="100">
<fx:Script>
<![CDATA[
import mx.core.IToolTip;
public var arrItemsKits:Array=[];
public var _text:String;
public function get text():String {
return _text;
}
public function set text(value:String):void {
}
protected function init():void
{
grid.dataProvider=arrItemsKits;
}
]]>
</fx:Script>
<mx:DataGrid id="grid" width="100%" height="100%">
<mx:columns>
<mx:DataGridColumn headerText="Code" dataField="itemPartNumber"/>
<mx:DataGridColumn headerText="Description" dataField="kitItemsNotes"/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
and i want it to fire it when i roll the mouse over a row from a datagrid, so i need to add an event listener(toolTipCreate) to the row of that grid.
Any ideas how can i solve this?
Thanks
Check out this
<!-- myDataGridTest.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.events.ListEvent;
import mx.core.IToolTip;
import mx.events.ToolTipEvent;
// holds the currently highlighted item
private var highlightedItem:Object;
// event listener to get our hands on the currently highlighted item.
private function getHighlightedItem(e:ListEvent):void {
highlightedItem = e.itemRenderer.data;
// Quick n dirty way to force the ToolTipManager to refresh our tooltip.
// We need to dispatch this by hand because the pointer never leaves myDataGrid
// between successive highlights.
myDataGrid.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OUT));
}
private function createTooltip(e:ToolTipEvent):void {
var tt:MyCustomTooltip = new MyCustomTooltip();
tt.firstName = highlightedItem.name;
tt.lastName = highlightedItem.surname;
// Contract with the tooltip manager: if it finds an IToolTip instance attached to
// the event, it uses that instance instead of creating the standard one.
e.toolTip = tt;
}
]]>
</mx:Script>
<mx:DataGrid id="myDataGrid" toolTip=" " toolTipCreate="createTooltip(event)" itemRollOver="getHighlightedItem(event)">
<mx:dataProvider>
<mx:Object name="john" surname="doe"/>
<mx:Object name="mike" surname="smith"/>
</mx:dataProvider>
</mx:DataGrid>
</mx:Application>
<!-- MyCustomTooltip.mxml -->
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" implements="mx.core.IToolTip"
backgroundColor="yellow" backgroundAlpha="0.6">
<mx:Script>
<![CDATA[
private var _firstName:String;
private var _lastName:String;
// Dummy implementations to comply with mx.core.IToolTip
public function get text():String {return null;}
public function set text(value:String):void {}
// properties and functions
public function set firstName(value:String):void {
_firstName = value;
invalidateProperties();
}
public function set lastName(value:String):void {
_lastName = value;
invalidateProperties();
}
override protected function commitProperties():void {
fName.text = _firstName;
lName.text = _lastName;
}
]]>
</mx:Script>
<mx:Label x="0" y="0" id="fName"/>
<mx:Label x="0" y="20" id="lName"/>
</mx:Canvas>
.
.
Or try something like this
.
.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="doInit();">
<mx:Script>
<!![CDATA[import mx.collections.ArrayCollection; // this holds the grid data
[Bindable]
private var myData:ArrayCollection = new ArrayCollection();private function doInit():void{
myData.addItem({fname:"Joe",lname:"Bloggs"});
myData.addItem({fname:"Joe1",lname:"Bloggs"});
}
private function buildToolTip(item:Object):String{
var myString:String = "";
if(item != null)
{
myString = myString + "Firstname : " + item.fname + "\n";
myString = myString + "Lastname : " + item.lname + "\n"
}
return myString;
}
]]>
</mx:Script>
<mx:DataGrid id="dGrid" dataProvider="{myData}" visible="true" dataTipFunction="buildToolTip">
<mx:columns>
<mx:DataGridColumn dataField="fname" headerText="FirstName" showDataTips="true" />
<mx:DataGridColumn dataField="lname" headerText="LastName" showDataTips="true" />
</mx:columns>
</mx:DataGrid>
</mx:Application>
I figured it out: On itemRollOver handler you add event.itemRenderer.addEventListener(ToolTipEvent.TOOL_TIP_CREATE, createTT);