Adobe Flex 4.5 Spark: Binding ItemRenderer Component to Parent - apache-flex

In Flex 3, it used to be possible to bind a component property within an itemRenderer via outerDocument. So for instance, if there was a image inside an itemRenderer that was only displayed on a given condition of the parent, something like this would work perfectly:
<mx:itemRenderer>
<mx:Component>
<mx:Label text="{data}"/>
<mx:Image id="img" visible="{outerDocument.ShowImage}" includeInLayout="{outerDocument.ShowImage}"/>
</mx:Component>
</mx:itemRenderer>
where the outer document (not the list, but the mxml the list is in) contained something like
[Bindable]
public function get ShowImage():void
{
return showImage;
}
public function set ShowImage(val:Boolean):void
{
showImage = val;
}
I've tried to do the same thing in Flex 4.5 using Spark item renderers using parentDocument, but it doesn't seem to be aware to the binding. When I do this in Flex 4.5, the itemRenderer doesn't seem to be aware when the parentDocument ShowImage changes.
Has anyone seen this issue and is able to offer a solution?
EDIT: Add Spark Source
As requested here is my spark source:
MyItemRenderer.mxml
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:Label id="myLabel" text="{data}/>
<s:Image src="something.png" visible="{parentDocument.ShowImage}" includeInLayout="{parentDocument.ShowImage}"/>
</s:ItemRenderer>
RendererContainer.mxml
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
private var showImage:Boolean = false;
[Bindable]
public function set ShowImage(val:Boolean):void
{
showImage = val;
}
public function get ShowImage():Boolean
{
return showImage;
}
]]>
</fx:Script>
<!-- Content Group -->
<s:List id="lstCell" width="100%" height="100%" itemRenderer="MyItemRenderer">
</s:List>
</s:Panel>
Ok so there is a checkbox in a wrapper outside of RendererContainer.mxml that dispatches a custom event that is handled by changing a Bindable Boolean. The change in that var then changes the ShowImage property on my RendererContainer component. I would expect that the binding would then be picked up by MyItemRenderer but it doesnt seem to be working.
So my outer wrapper would access ShowImage like this
<comp:RendererContainer id="myId" ShowImage="{myCheckbox.selected}"/>

I think this should do the trick for you, YourTypeHere would be the class of the containing
object, make sure the ShowImage property is public and bindable.
<mx:itemRenderer>
<mx:Component>
<mx:Script>
<![CDATA[
import YourTypeHere;
]]>
</mx:Script>
<mx:Label text="{data}"/>
<mx:Image id="img"
visible="{YourTypeHere(this.parent.ShowImage)}"
includeInLayout="{YourTypeHere(this.parent.ShowImage)}"/>
</mx:Component>
</mx:itemRenderer>
P.s. please don't name properties with a starting uppercase letter, including getters, consider naming it showImage and your private var to something like _showImage instead :D

Your getter seems to have return type as void. Change that to Boolean
[Bindable]
public function get ShowImage():Boolean
{
return showImage;
}
public function set ShowImage(val:Boolean):void
{
showImage = val;
}

This will help.
<s:Image src="something.png" visible="{RendererContainer(ListSkin(parentDocument).parentDocument).ShowImage}" includeInLayout="{RendererContainer(ListSkin(parentDocument).parentDocument).ShowImage}"/>

Following works perfectly fine:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
private var showImage:Boolean = false;
[Bindable]
public function set ShowImage(val:Boolean):void
{
showImage = val;
}
public function get ShowImage():Boolean
{
return showImage;
}
]]>
</fx:Script>
<s:CheckBox label="Select" change="{ShowImage = !ShowImage}"/>
<!-- Content Group -->
<s:List id="lstCell" width="100%" height="100%" dataProvider="{new ArrayCollection(['A','B'])}">
<s:itemRenderer>
<fx:Component>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true">
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<s:Label id="myLabel" text="{data}"/>
<s:Button label="something.png" visible="{outerDocument.ShowImage}" includeInLayout="{outerDocument.ShowImage}"/>
</s:ItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>
</s:Panel>
</s:WindowedApplication>

Related

How to access MXML component instance in ItemRenderer

I have been developing an Adobe Flex (v3.5 Flex SDK) based application and I have a question on How we can access (call) a method written in MXML file (embeded in script tag) from the ItemRenderer file.
The MXML component has a datagrid and for one of the columns, the itemrenderer is my own custom item renderer.
In my custom item renderer, for some event I need to call a method which exist in its parent MXML component. How do we get access to its parent MXML instance ?
I have explored for this in google and found that we can access to 'data' object which refers to the dataProvider of the datagrid. But I wanted access to the instance of MXML component (so that I can call a method in it) which has the datagrid.
The AdvancedDataGridColumn in AdvancedDataGrid is like this
<mx:AdvancedDataGridColumn dataField="total" headerText="Total" width="120" itemRenderer="renderers.MyItemRenderer"/>
Here MyItemRenderer is a separate action script file.
Appreciate the response.
Thanks
Raagu
As Raghavendra Nilekani suggested This works:
TestGrid.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">
<fx:Script>
<![CDATA[
[Bindable]
public var data:Array = [
{name:"name",value:"valeu1",timestamp:"423423"},
{name:"name1",value:"valeu2",timestamp:"423423"},
{name:"name2",value:"valeu3",timestamp:"423423"},
{name:"name3",value:"valeu5",timestamp:"423423"}
]
public function calculateValue():Number{
return Math.random();
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<mx:VBox height="100%" width="100%">
<mx:AdvancedDataGrid dataProvider="{data}">
<mx:columns>
<mx:AdvancedDataGridColumn itemRenderer="ItemRenderer">
</mx:AdvancedDataGridColumn>
</mx:columns>
</mx:AdvancedDataGrid>
</mx:VBox>
</s:Application>
e ItemRendere.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
focusEnabled="true"
addedToStage="mxadvanceddatagriditemrenderer1_addedToStageHandler(event)"
>
<fx:Script>
<![CDATA[
[Bindable]
var value:Number;
import mx.containers.VBox;
import mx.controls.AdvancedDataGrid;
protected function mxadvanceddatagriditemrenderer1_addedToStageHandler(event:Event):void
{
var grid:AdvancedDataGrid = ((AdvancedDataGrid)(this.owner));
var box:VBox = ((VBox)(grid.owner))
var comp:TestGrid = (TestGrid)(box.owner);
value = comp.calculateValue();
}
]]>
</fx:Script>
<s:Label id="lblData" top="0" left="0" right="0" bottom="0" text="{value}" />
</s:MXAdvancedDataGridItemRenderer>
Anyway I agree with zenbeni that this lead to a not reausable item renderer.

Adobe flex from a list componet to radio buttons

I have tried to do this many ways but for the life of me cannot think how to. Basically I have a list. When an item on the list is selected the radio button labels change. However, I want a label and text area to appear saying once the user has clicked on the radio button if it is right or not.
Code so far: -
<s:VGroup x="103" y="130" width="123" height="125">
<s:RadioButton id="RadioButton1" label="{data.QuestionsRadioButton1}" groupName="QuestionsTestRadioButtons" click="RadioButton1_clickHandler(event)"/>
<s:RadioButton label="{data.QuestionsRadioButton2}" groupName="QuestionsTestRadioButtons" click="radiobutton1_clickHandler(event)" />
<s:RadioButton id="RadioButton3" label="{data.QuestionsRadioButton3}" groupName="QuestionsTestRadioButtons" click="radiobutton2_clickHandler(event)"/>
</s:VGroup>
I will not post all the code as we will be here forever. However, is there a way maybe an if function? To say if the radio button clicked actually is the right answer or not?
Any suggestions would be helpful
Thank You
My attempt to draft a complete example:
Questionaire.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:local="*">
<fx:Declarations>
<s:ArrayCollection id="questions">
<local:Question text="It is raining …">
<s:ArrayCollection>
<local:Answer text="Men"/>
<local:Answer text="Cats and dogs" correct="true"/>
<local:Answer text="Candy"/>
</s:ArrayCollection>
</local:Question>
<local:Question text="The sky is …">
<s:ArrayCollection>
<local:Answer text="Blue" correct="true"/>
<local:Answer text="Orange" correct="true"/>
<local:Answer text="Grey" correct="true"/>
<local:Answer text="Green"/>
</s:ArrayCollection>
</local:Question>
</s:ArrayCollection>
</fx:Declarations>
<s:DataGroup dataProvider="{questions}" itemRenderer="QuestionRenderer">
<s:layout>
<s:VerticalLayout gap="24"/>
</s:layout>
</s:DataGroup>
</s:Application>
QuestionRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:DataRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
[Bindable("dataChange")]
public function get question():Question {
return data as Question;
}
]]>
</fx:Script>
<fx:Declarations>
<s:RadioButtonGroup id="answerGroup"/>
</fx:Declarations>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Label fontWeight="bold" text="{question.text}"/>
<s:DataGroup dataProvider="{question.answers}">
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<s:itemRenderer>
<fx:Component>
<s:DataRenderer>
<fx:Script>
<![CDATA[
import spark.components.RadioButtonGroup;
public function get answerGroup():RadioButtonGroup {
return outerDocument.answerGroup;
}
]]>
</fx:Script>
<s:RadioButton groupName="answerGroup" label="{data.text}" value="{data}"/>
</s:DataRenderer>
</fx:Component>
</s:itemRenderer>
</s:DataGroup>
<s:Label visible="{answerGroup.selectedValue}" text="This is {answerGroup.selectedValue.correct ? 'correct' : 'incorrect'}."/>
</s:DataRenderer>
Question.as
package {
import mx.collections.ArrayCollection;
[Bindable]
[DefaultProperty("answers")]
public class Question {
public var text:String;
public var answers:ArrayCollection;
}
}
Answer.as
package {
[Bindable]
public class Answer {
public var text:String;
public var correct:Boolean = false;
}
}

Close a Callout inside a View in Flex

I have this ViewNavigator inside a callout and the callout displays a view inside it using firstView="views.ListMenusHomeView" . Now how can I close the callout from ListMenusHomeView? Hope someone can help.
Here is my code for the callout:
<?xml version="1.0" encoding="utf-8"?>
<s:Callout xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
contentBackgroundAppearance="none"
height="300" width="300">
<fx:Declarations>
<fx:XML id="menu" source="xmldata/menu2.xml" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import spark.events.PopUpEvent;
protected function back(event:MouseEvent):void {
if(viewNav.length>1)
viewNav.popView();
}
]]>
</fx:Script>
<s:ViewNavigator id="viewNav" width="100%" height="100%" firstView="views.ListMenusHomeView">
<s:navigationContent>
<s:Button label="Back" click="back(event)"/>
</s:navigationContent>
<s:actionContent>
<s:Button label="Cancel" click="close(false)" emphasized="true"/>
</s:actionContent>
</s:ViewNavigator>
</s:Callout>
You see that there is a ViewNavigator which holds the ListMenusHomeView. This is the code for the ListMenusHomeView.
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="Main Menu" creationComplete="onCreationComplete()">
<fx:Declarations>
<fx:XML id="menu" source="xmldata/menu2.xml" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.adobe.serializers.xml.XMLDecoder;
import mx.collections.ArrayCollection;
import spark.events.IndexChangeEvent;
[Bindable]
private var dataArray:ArrayCollection = new ArrayCollection();
private var object:DataArray = new DataArray();
private function onCreationComplete() : void{
var decoder:XMLDecoder = new XMLDecoder();
var resultObj:Object = decoder.decode(menu);
dataArray = object.onCreationComplete(menu, menu.menuitem, resultObj, resultObj.menuitem);
}
protected function list1_changeHandler(event:IndexChangeEvent):void
{
}
]]>
</fx:Script>
<s:List id="tileLayout"
width="100%" height="100%"
verticalScrollPolicy="off" horizontalScrollPolicy="on"
pageScrollingEnabled="true" dataProvider="{dataArray}"
itemRenderer="renderers.iconList2" change="list1_changeHandler(event)">
<s:layout>
<s:TileLayout orientation="columns" requestedRowCount="3"
verticalGap="20" horizontalGap="20"/>
</s:layout>
</s:List>
Now I want to close MyCallout whenever I click an icon inside ListMenusHomeView. The function list1_changeHandler(event:IndexChangeEvent) is responsible for that one.
What should I do?
The Callout class has a close() method, so you basically just need to access the ListMenusHomeViews parentDocument (which would be your "viewNav" ViewNavigator) and its parentDocument, which should be your ListMenusHomeView.
I haven't tested it but you might fiddle around with the parentDocument, parent and owner properties to access the correct object. Try them with a simple trace and you'll be up and running in no time.

Drag and drop item renderer(panel) within list

I have a spark List,its item renderer is a panel,and in the panel there are some components such as Textinput,now I want to drag and drop a panel within the List,how can I do that,could you pls show me the code,thanks.
The list in flex has a default drag and drop functionality. So basically all you need to do is to set 3 properties to true to your list:
dragMoveEnabled, dragEnabled and dropEnabled. So your list if you add it from mxml will look like this:
<s:List dataProvider="{yourDataProvider}" dragMoveEnabled="true" dragEnabled="true" dropEnabled="true" />
For more details about these 3 properties you can check the spark list documentation:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/components/List.html#dragMoveEnabled
thanks for your help.Now I catch an error while draging the itemRenderer(my flex sdk is 4.5.1).
My list itemRenderer:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer 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="100%" height="100%">
<fx:Script>
<![CDATA[
import mx.events.CloseEvent;
override public function set data(value:Object ) : void{
super.data = value;
}
protected function closeHandler(event:CloseEvent):void
{
//ToDo
}
]]>
</fx:Script>
<s:TitleWindow x="0" y="0" title="{data.label}"
width="100%" height="100%" creationPolicy="all"
skinClass="skin.titleWindowSkin"
close="closeHandler(event)">
<s:Label text="{data.value}"/>
<s:TextInput x="123" y="58" text="#{data.value}"
focusIn="parentDocument.owner.dragEnabled=false"
focusOut="parentDocument.owner.dragEnabled=true"/>
</s:TitleWindow>
</s:ItemRenderer>
While draging,catch an error like:
Error: Skin for DragProxy261.ListItemDragProxy260.DspDesktopItemRenderer262._DspDesktopItemRenderer_TitleWindow1.titleWindowSkin264.Group265.contents._titleWindowSkin_Group5.contentGroup._DspDesktopItemRenderer_TextInput1 cannot be found.
at spark.components.supportClasses::SkinnableComponent/attachSkin()[E:\dev\4.5.1\frameworks\projects\spark\src\spark\components\supportClasses\SkinnableComponent.as:698]

Custom component dataGrid selectionMode as a property

I have a custom component of which have a advancedDataGrid inside it. I want this component to be reusable so need is set the datagid selectionMode as a component property.
In mxml i want set property like this:
<comp:MyComp itemDataGridSelectionMode="singleCell" .../>
Inside MyComp actionScript i have a metatag like this:
[Inspectable(enumeration="singleRow, multipleRows, singleCell, multipleCells", defaultValue="singleRow")]
public var itemDataGridSelectionMode:String;
How do i bind this itemDataGridSelectionMode variable to advancedDatagrid selectionMode?
UPDATE: Here is a small test application fully working code:
<!--MyComp.mxml-->
<?xml version="1.0" encoding="utf-8"?>
<s:Group 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="638" height="500">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
[Inspectable(enumeration="singleRow, multipleRows, singleCell, multipleCells", defaultValue="singleRow")]
public function set itemsSelectionMode(value:String):void
{
this.adgItems.selectionMode = value;
}
public function get itemsSelectionMode():String
{
return this.adgItems.selectionMode;
}
]]>
</fx:Script>
<mx:AdvancedDataGrid id="adgItems" designViewDataType="flat" width="100%" height="100%">
<mx:columns>
<mx:AdvancedDataGridColumn headerText="Column 1" dataField="col1"/>
<mx:AdvancedDataGridColumn headerText="Column 2" dataField="col2"/>
<mx:AdvancedDataGridColumn headerText="Column 3" dataField="col3"/>
</mx:columns>
</mx:AdvancedDataGrid>
</s:Group>
<!-- 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" minWidth="955" minHeight="600" xmlns:comp="*">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<comp:MyComponent x="272" y="86" itemsSelectionMode="singleCell"/>
</s:Application>
Error: Invalid value: multipleRows. It must be one of singleRow, multipleRows, singleCell, multipleCells.
Where you have your public var within your custom component, do this:
[Inspectable(enumeration="singleRow, multipleRows, singleCell, multipleCells", defaultValue="singleRow")]
public function set itemDataGridSelectionMode(value:String):void
{
advancedDatagrid.selectionMode = value;
}
public function get itemDataGridSelectionMode():String
{
return advancedDatagrid.selectionMode;
}
I guess you can set the itemDataGridSelectionMode as [Bindable] and then can bind it with the selectionMode property of the AdvancedDataGrid.
One way is:
BindingUtils.bindProperty(datagridId, 'selectionMode', this, itemDataGridSelectionMode);
OR Use a setter method instead of variable definition.

Resources