Flex selectedItem problems - apache-flex

I have encountered somthing a little strange in flex, possibly somthing im doing wrong
but im not sure.
In two cases which i have noticed, when there is only 1 item in a s:List or s:DropDownList
for some reason when using list.selectedItem it appears as null. Using requireSelection="true"
i know this isnt the case.
Has anyone else seen anything similar? or am i doing it completly wrong?
Thanks
Jon
Edit: In the code bellow it happens when clicking the edit document, which calls the open edit method
------------ Added Code ---------------------------
I have removed small portions to make it more readable
<s:TitleWindow width="486" height="300" title="Document Store"
xmlns:tmsbean="services.tmsbean.*"
close="close()">
<fx:Declarations>
<s:CallResponder id="getAllAttachedDocumentsResult"/>
<tmsbean:TMSBean id="tMSBean" showBusyCursor="true"/>
<s:CallResponder id="removeDocumentLinkResult" result="getDocumentList()"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
private static var documentStoreView:DocumentStoreView = null;
[Bindable]
private var attachedToMenomic:String;
public static function getInstance():DocumentStoreView
{
if(documentStoreView == null){
documentStoreView = new DocumentStoreView();
DocumentForm.getInstance().addEventListener(DocumentFormEvent.DOCUMENT_ATTACHED,documentStoreView.getDocumentList);
}
return documentStoreView;
}
public function open(menomic:String,parent:DisplayObject):void
{
attachedToMenomic = menomic;
getDocumentList();
PopUpManager.addPopUp(documentStoreView,parent,true);
PopUpManager.centerPopUp(documentStoreView);
y = y - 80;
}
public function close():void
{
PopUpManager.removePopUp(documentStoreView);
}
private function getDocumentList(evt:DocumentFormEvent = null):void
{
getAllAttachedDocumentsResult.token = tMSBean.getAllAttachedDocuments(attachedToMenomic);
}
private function openEdit():void{
var editDsi:DocumentStoreItem = documentList.selectedItem as DocumentStoreItem;
Alert.show(editDsi.documentName);
DocumentForm.getInstance().openInEditMode(editDsi,this);
}
]]>
</fx:Script>
<s:VGroup left="10" top="10" right="10" bottom="10">
<s:List width="100%" height="100%" id="documentList" itemRenderer="com.documentStore.DocumentItemListRenderer"
dataProvider="{Utilitys.toArrayCollection(getAllAttachedDocumentsResult.token.result)}" />
<s:HGroup horizontalAlign="right" width="100%">
<s:Button label="Attach Document" click="{DocumentForm.getInstance().open(attachedToMenomic,this)}"/>
<s:Button label="Edit Document" click="openEdit()"/>
</s:HGroup>
</s:VGroup>
</s:TitleWindow>

By default Spark's DropDownList displays a prompt if selectedIndex is -1, which will be the case if requireSelection is false and you have not otherwise set the list to a specific item. This would correspond with selectedItem being null.
The Spark ComboBox does something similar but it has a TextInput as you can type into it.

Related

labelField asking

hi guys i have xml database how to call phone and display in label ?
i already have label Field but i want to call phone in side the Field
how ?
this my cod
<s:List id="lst" x="73" y="197" width="295" height="214" change="lst_changeHandler(event)"
dataProvider="{arr}" fontSize="30" fontWeight="bold"
textAlign="right">
<s:labelField>RestaurantsKuwaiti</s:labelField>
http://www.mlfnt.com/lives6/13510357301.png
First of all, your xml is not like a list:
<RestaurantsKuwaiti>
...
<RestaurantsOther>
...
I think it should be like:
<Restaurants>
<name>Kuwaiti</name>
</Restaurants>
<Restaurants>
<name>Syria</name>
</Restaurants>
...
use labelFunction can solve your problem:
<fx:Script>
<![CDATA[
import mx.collections.XMLListCollection;
private var xml:XML =
<dataroot>
<alldata>
<ID>1</ID>
<Main>2</Main>
<RestaurantsKuwaiti>
<phone>55555555</phone>
</RestaurantsKuwaiti>
</alldata>
</dataroot>;
[Bindable]
private var dataList:XMLListCollection = new XMLListCollection(xml.alldata);
private function labelFunc(item:Object):String {
return item.RestaurantsKuwaiti.phone;
}
]]>
</fx:Script>
<s:List dataProvider="{dataList}" labelFunction="labelFunc"/>
as I mentioned above, the "dataList" has only one item: "alldata".

Flex disable draginitiator?

I'm trying to disable the draginitiator, that's the semi-transparant object when you drag something.
Does anyone know how to do this?
EDIT Code
<s:List id="dg_ads" top="75" bottom="0" width="100%" borderVisible="false"
dragEnabled="true" dropEnabled="true" dragMoveEnabled="true"
dragComplete="dg_ads_dragCompleteHandler(event)"
doubleClickEnabled="true" doubleClick="dg_ads_doubleClickHandler(event)"
contentBackgroundColor="#FFFFFF">
<s:layout>
<s:TileLayout useVirtualLayout="false" clipAndEnableScrolling="false"
horizontalGap="5" verticalGap="5" />
</s:layout>
</s:List>
Create a custom list class that extends spark List and override createDragIndicator() method.This is method is used by the DragManager to create the dragProxy(The image you will see when a drag operation is in progress).
override public function createDragIndicator():IFlexDisplayObject
{
var dragIndicator:UIComponent;
dragIndicator = new UIComponent();
dragIndicator.width = 0;
dragIndicator.height = 0;
return dragIndicator;
}
Use the custom list instead of spark List in your application
From this question:
Try:
event.dragInitiator.visible = false;
or create your own version of the DragProxy class and remove the portions you don't want.

apply animation to UI component via actionscript in flex issue

Here is my entire application. Pretty easy stuff.
I have two panels that have a click event on them. However, both call the same function for some reason. When I have only one panel visible the animation works correctly. However if I add another to the stage on the click event both panels animate at the same time.
I just dont get what I'm doing wrong. My function is looking for only the current target but apparently I must not be doing that correctly because it's animating both panels and not just the panel the I clicked. My expected result is to animate only the clicked panel.
Any help would be really appreciated.
<?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"
applicationComplete="application1_applicationCompleteHandler(event)"
left="20">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<!--<s:Sequence id="EffectsHide">-->
<!--<s:Rotate id="rotatein" target="{panel1}" angleBy="90"/>-->
<mx:Parallel id="EffectsHide">
<s:Rotate3D angleYFrom="0" angleYTo="360" duration="1000" />
<s:Resize id="shrink" duration="1000" heightBy="-170" />
<s:Move3D id="MoveIn" yBy="{_applicationHeighth-30}" duration="1000"/>
</mx:Parallel>
<!-- </s:Sequence>-->
<s:Sequence id="EffectsShow">
<s:Rotate id="rotateOut" target="{panel1}" angleBy="-90"/>
<s:Move id="MoveOUt" target="{panel1}" xBy="-30"/>
<s:Resize id="grow" target="{panel1}" duration="2000" widthBy="{_applicationWidth}" heightBy="{_applicationHeighth}"/>
</s:Sequence>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.effects.Effect;
import mx.effects.Parallel;
import mx.events.FlexEvent;
private var myParallel:Parallel = new Parallel();
private var myParallelReverse:Parallel = new Parallel();
[Bindable]
public var _applicationWidth:Number = new Number();
[Bindable]
public var _applicationHeighth:Number = new Number();
[Bindable]
public var Maximized :Boolean = true;
public var minimized :Boolean = false;
public function rotateTarget(event:Event):void{
//define the rotate effect
/*
var myRotated3d:Rotate3D= new Rotate3D(event.currentTarget);
myRotated3d.angleYFrom = 0;
myRotated3d.angleYTo=360;
myRotated3d.duration=1000;
*/
if(Maximized == true)
{
//EffectsHide.target(_target);
//EffectsHide.stop();
//EffectsHide.play();
//var myRotated3d:Rotate3D= new Rotate3D(event.currentTarget);
//myRotated3d.angleYFrom = 0;
//myRotated3d.angleYTo=360;
//myRotated3d.duration=1000
var myResize:Resize = new Resize(event.currentTarget);
myResize.heightBy = -160;
myResize.duration = 500;
var myMove3D:Move= new Move(event.currentTarget);
myMove3D.yTo=_applicationHeighth-30;
myMove3D.duration=500;
//myParallel.addChild(myRotated3d);
myParallel.addChild(myResize);
myParallel.addChild(myMove3D);
//this.invalidateDisplayList();
//this.validateNow();
//this.panel1.validateProperties();
minimized= true;
Maximized = false;
myParallel.stop();
myParallel.play();
trace('tried to run')
}
else if (Maximized == false){
trace(numElements)
//trace(getElementIndex(panel1));
//var myRotated3drever:Rotate3D= new Rotate3D(event.currentTarget);
//myRotated3drever.angleYFrom = 0;
//myRotated3drever.angleYTo=-360;
//myRotated3drever.duration=1000;
var myResizerever:Resize = new Resize(event.currentTarget);
myResizerever.heightTo= 200;
myResizerever.duration =500;
var myMove3Drever:Move = new Move(event.currentTarget);
myMove3Drever.yTo=(0);
myMove3Drever.duration=500;
myParallelReverse.addChild(myMove3Drever);
myParallelReverse.addChild(myResizerever);
//myParallelReverse.addChild(myRotated3drever);
myParallelReverse.play();
Maximized = true;
}
}
protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
_applicationWidth = stage.width;
_applicationHeighth = stage.height;
}
protected function _butt_clickHandler(event:MouseEvent):void
{
trace(panel1.x);
trace(panel1.y);
trace(panel1.height);
}
]]>
</fx:Script>
enter code here
<mx:Canvas>
<mx:Panel id="panel1" title="Label1" x="400" y="0" width="200" height="200" click="rotateTarget(event)"/>
<mx:Panel id="panel2" title="Label2" x="0" y="0" width="200" height="200" click="rotateTarget(event)"/>
</mx:Canvas>
<!--<s:Panel id="panel2" y="240" title="Label2" width="200" height="200" click="rotateTarget(event)"/>
-->
<!--</s:VGroup>-->
<s:Button x="250" id="_butt" click="_butt_clickHandler(event)"/>
<s:Button x="250" y="20" id="_butt2" click="rotateTarget(event)"/>
</s:Application>
My two best guess without the full code (the bit with the panels):
You should be using event.target rather than event.currentTarget.
You bound the 'EffectsHide' (all IDs should be lowercase by the way) parallel directly to 'panel1' so whenever it gets plays that is the component it is going to target.
*I see now that you keep adding new animation effects created in the rotatetarget function to the parallel 'myParallel'. You do not however remove them at any given point so it just keeps on playing all the effects you ever added to it each time it get's played. You should just add them once on application setup and then just play them.

how to show a tooltip on a disabled control?

I'm displaying a list of buttons, some of which might be disabled. I need to show a tooltip on the disabled buttons with an explanation of why it's disabled, but it seems I can't disable the button without disabling the tooltip. Is there a simple way around this?
Wrap the Button in a Group, and apply the toolTip to the group instead.
<s:Group toolTip="My toolTip">
<s:Button enabled="false"/>
</s:Group>
It's a bit ugly, but it works.
One way to do this is to override the enabled getter and setter to do what you want. So in my case, I still wanted most mouse events to fire, just not the click event.
<?xml version="1.0" encoding="utf-8"?>
<s:Button buttonMode="true" click="handleClick(event)" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
public var data:Object;
private var _enabled:Boolean = true;
public override function get enabled():Boolean
{
return _enabled;
}
public override function set enabled(value:Boolean):void
{
_enabled = value;
invalidateDisplayList();
dispatchEvent(new Event("enabledChanged"));
invalidateSkinState();
}
protected function handleClick(event:MouseEvent):void
{
if (!_enabled)
{
event.stopPropagation();
}
}
]]>
</fx:Script>
</s:Button>
Since mouse events now fire, the tooltips work again.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.managers.ToolTipManager;
import mx.controls.ToolTip;
private var tooltip:ToolTip;
private var p:Point;
private function whyDisable():void
{
//calculate the button position , so that roll over shows the tooltip
p=new Point();
p=localToGlobal(new Point(btn.x,btn.y));
if(btn.enabled==false)
tooltip = ToolTipManager.createToolTip('Button is disabled',p.x+(btn.width/2),p.y-20,'errorTipAbove') as ToolTip;
else
tooltip=ToolTipManager.createToolTip('Button is enabled',p.x+(btn.width/2),p.y-20,'errorTipAbove') as ToolTip;
}
]]>
</mx:Script>
<mx:VBox height="100%" width="100%" horizontalAlign="center" verticalAlign="middle">
<mx:Button id="btn" label="Show Tooltip" buttonDown="trace('ankur')" autoRepeat="true" enabled="true" rollOver="whyDisable();" rollOut="{ToolTipManager.destroyToolTip(tooltip);}"/>
</mx:VBox>
</mx:Application>
Hi, this application works on the disabled button,I used ToolTipManager to do this,
i hope this works for you
have a gr8 time
Ankur Sharma
The best choice for me was to put a void label around and in front of the element. Then, if necessary, I set the element to disable and the tooltip works in the label. If not, I put sent the label to back. It works pretty well.
if (new MainListsAdmin(this.mainApp).temInvestimentoComAqueleTipo(t)) {
deletarGroupInto.setTooltip(new Tooltip("Há investimentos vinculados a Tipo de Investimento.\nDeleção bloqueada."));
this.deletarButton.setDisable(true);
}else{
deletarGroupInto.toBack();
}
You will need to use the ToolTipManager class to create and destroy the tool tips manually.
This article should give you all the info you need to accomplish this:
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf60d65-7ff6.html

Flex DataGrid with ComboBox itemRenderer

I'm going spare trying to figure out the "correct" way to embed a ComboBox inside a Flex (3.4) DataGrid. By Rights (e.g. according to this page http://blog.flexmonkeypatches.com/2008/02/18/simple-datagrid-combobox-as-item-editor-example/) it should be easy, but I can't for the life of me make this work.
The difference I have to the example linked above is that my display value (what the user sees) is different to the id value I want to select on and store in my data provider.
So what I have is:
<mx:DataGridColumn headerText="Type" width="200" dataField="TransactionTypeID" editorDataField="value" textAlign="center" editable="true" rendererIsEditor="true">
<mx:itemRenderer>
<mx:Component>
<mx:ComboBox dataProvider="{parentDocument.transactionTypesData}"/>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
Where transactionTypesData has both 'data' and 'label' fields (as per what the ComboBox - why on earth it doesn't provide both a labelField and idField I'll never know).
Anyway, the above MXML code doesn't work in two ways:
The combo box does not show up with any selected item.
After selecting an item, it does not store back that selected item to the datastore.
So, has anyone got a similar situation working?
While Jeff's answer is a partial answer for one approach for this (see http://flex.gunua.com/?p=119 for a complete example of this being used to good effect), it isn't as general as I wanted.
Thankfully, I finally found some great help on Experts Exchange (the answers by hobbit72) describes how to create a custom component that works in a grid as a ItemRenderer.
I've extended that code to also support using the combo box as an ItemEditor as well. The full component is as follows:
<?xml version="1.0" encoding="utf-8"?>
<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>
Using this component is straight forward. As an ItemRenderer:
<mx:DataGridColumn headerText="Child" dataField="PersonID" editable="false" textAlign="center">
<mx:itemRenderer>
<mx:Component>
<fx:GridComboBox dataProvider="{parentDocument.childrenData}" labelField="Name" lookupField="PersonID" change="dispatchEvent(new mx.events.DataGridEvent(mx.events.DataGridEvent.ITEM_FOCUS_OUT, true, true))"/>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
Using this component is straight forward. And as an ItemEditor:
<mx:DataGridColumn labelFunction="lookupChildName" headerText="Child" dataField="PersonID" editable="true" editorDataField="selectedItemKey">
<mx:itemEditor>
<mx:Component>
<fx:GridComboBox dataProvider="{parentDocument.childrenData}" labelField="Name" lookupField="PersonID" change="dispatchEvent(new mx.events.DataGridEvent(mx.events.DataGridEvent.ITEM_FOCUS_OUT, true, true))"/>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
Note that when using it as an ItemEditor, a custom labelFunction (that looks up the Name from the PersonID in my case) must be used, otherwise you only see the key in the grid when the field isn't being edited (not a problem if your keys/values are the same).
Note that in my case, I wanted the item focus out event to propogate up to provide immediate feedback to the user (my DataGrid has itemFocusOut="handleChange()"), hence the change event creating an ITEM_FOCUS_OUT event.
Note that there are probably simpler ways to have a ComboBox as an ItemEditor when you don't mind the ComboBox only shown when the user clicks on the cell to edit. The approach I wanted was a generic way to show a combo box in a DataGrid for all rows, and being editable and with decent event propogation.
The easiest way to add itemRenderers to DataGrids is to make a custom MXML component. In your case make a canvas, HBox, or VBox as the custom component and add the combobox as a child.Set the dataProvider on the dataGrid itself and assign the itemRenderer to the column, and then override the set data function of the itemRenderer to access all data from the given data provider for that instance as seen below:
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
override public function set data(value:Object):void{
trace(value.data);
trace(value.name);
}
]]>
</mx:Script>
<mx:ComboBox width="100%" height="100%" id="myComboBox"/>
</mx:HBox>
This method will be called for each instance of the itemRenderer
In my case I used a spark datagrid where one of the columns has an ItemRenderer that utilises a DropDownListBox. My problem was that when my item list change, the DropDownLists doesn't get updated with the new dataProvider. To solve this, I had to pass the dataProvider for the DropDownListBox as part of the data (of the ItemRenderer), and then by overriding the setter of the data to just assign the DropDownlListBox's dataProvider. Probably a bit of overhead, but if someone have a better solution, please let me know:
<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">
<fx:Script>
<![CDATA[
override public function set data(v : Object) : void {
super.data = v;
if (v == null)
return;
dropDown.dataProvider = data.dataProvider;
}
]]>
</fx:Script>
<s:DropDownList id="dropDown" width="100%" height="100%" dataProvider="{data.dataProvider}" labelField="name"/>

Resources