Updating view spark.components.List - actionscript-3

I am using a List component inside an itemRenderer. The main user interaction involves dragging an item from the List in one renderer and dropping it in another.
My problem: When the data object is updated I want the Lists' height to be modified according to the number of objects in the dataprovider(dp), which is passed to the List from the data object. Now I have tried to invalidate the display of the List, refresh its dp and have tried putting this line assets.length > 0 ? assetList.percentHeight = 100 : assetList.height = 10; in other event handlers, such as dragdrop handlers, collection event handlers for the dp etc. I have also tried refreshing the dp for the List component that is using this renderer. The view does eventually get updated but only if I resize the list, or use the scroller or when I begin dragging a new List item but never after the drop.
<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" width="100%" creationComplete="init()" currentState="collapsed">
<fx:Script>
<![CDATA[
[Bindable] private var itemRenderer:ClassFactory;
[Bindable] private var colWidth:Number = 100;
[Bindable] private var assets:ArrayCollection = new ArrayCollection;;
public function init():void{
itemRenderer = new ClassFactory(DefaultRenderer);
this.addEventListener(FlexEvent.DATA_CHANGE, onDataChange);
}
private function onDataChange(e:FlexEvent):void {
assets = data.assets;
trace(data.name, assets.length);
assets.length > 0 ? assetList.percentHeight = 100 : assetList.height = 10;
}
]]>
</fx:Script>
<s:Group width="100%">
<s:layout>
<s:VerticalLayout gap="0" />
</s:layout>
<s:ToggleButton
id="viewToggle"
label="{data.name}"
width="100%"
height="50"
/>
<s:List id="assetList"
width="100%"
dataProvider="{assets}"
height = "10"
top="0" left="0" bottom="0" right="0"
dragEnabled="true"
allowMultipleSelection="true"
dragMoveEnabled="true"
dropEnabled="true"
itemRenderer="{itemRenderer}"
>
<s:layout>
<s:TileLayout requestedColumnCount="2"
horizontalGap="0" verticalGap="0"
columnWidth="{colWidth}" rowHeight="{colWidth}"/>
</s:layout>
</s:List>
</s:Group>
</s:ItemRenderer>

In your onDataChange method try this:
itemRenderer = null;
itemRenderer = new ClassFactory(DefaultRenderer);

Related

Dynamically generated MXML data doesn't get rendered

So I have a requirement to display dynamically generated data in the view.
For this, my idea was to create a mxml file and then use it as an object. Fill the data in the ibject and then use addChild to display it. But even after adding all the data. The dynamically generated mxml file doesn't gets displayed.
Code
BuyTogetherGrid.MXML
<?xml version="1.0" encoding="utf-8"?>
<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml" width="80" height="60" xmlns:image="org.commodity.detail.image.*">
<mx:HBox>
<image:ImageBox id="buyTogetherImg"></image:ImageBox>
<mx:VBox id="textInfo">
<mx:Box id="commonNameBox">
<mx:Label id="commonName">
</mx:Label>
</mx:Box>
<mx:Box id="commonPriceBox">
<mx:Label id="commonPrice">
</mx:Label>
</mx:Box>
</mx:VBox>
</mx:HBox>
<mx:Script>
<![CDATA[
public function createGrid():void{
this.buyTogetherImg = new ImageBox();
this.commonName = new Label();
this.commonPrice = new Label();
}
]]>
</mx:Script>
</mx:Box>
This is my MXMl File. My idea was to create an object of this mxml object. Add data to buyTogetherImg, CommonName, CommonPrice and then use addChild
Part where I set the data
<mx:HBox id="buyTogetherBox" width="100%" borderColor="black">
</mx:HBox>
The upper HBox is the container where I will keep all my generated object
var buyTogetherBox : BuyTogetherGrid = new BuyTogetherGrid();
buyTogetherBox.createGrid();
for each(var item:cmListItem in commod.items){
if(item.dataFormat == 2){
buyTogetherBox.buyTogetherImg.imgData = item.value as ImageData;
} else if(item.dataFormat == 0){
buyTogetherBox.commonName.text = item.value.toString();
} else if(item.dataFormat == 3){
buyTogetherBox.commonPrice.text = StringUtil.numToStrPrice(item.value as Number);
}
}
this.buyTogetherBox.addChild(buyTogetherBox);
}
The code check some conditions and add the data. However the buyTogetherBox is not visible. But if I try something like
this.buyTogetherBox.addChild(buyTogetherBox.buyTogetherImg);
then i can see the image in the H:Box.
I am pretty new to Flex. so may be I would have missed something
You are leaving the statically created instances of the label and image control unused and creating new instances instead. Basically, the entire createGrid() function is unnecessary. You already have the controls created in MXML. Just use them with creating new instances.
var grid:BuyTogetherGrid = new BuyTogetherGrid();
grid.addEventListener(FlexEvent.CREATION_COMPLETE, this.grid_creationCompleteHandler);
Elsewhere in the same class...
private function grid_creationCompleteHandler(event:FlexEvent):void
{
// Set your properties here
}
As Pranav said it takes some time to create MXML components and if you try to assess them immediately you will get a null pointer exception because they don't exist yet. A quick and dirty solution is to make public variables in your BuyTogetherGrid.MXML and then bind the text properties to these variables, like
<?xml version="1.0" encoding="utf-8"?>
<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml" width="80" height="60" xmlns:image="org.commodity.detail.image.*">
<fx:Script>
<![CDATA[
[Bindable] public var imageData:ImageData;
[Bindable] public var name:String;
[Bindable] public var price:String;
]]>
</fx:Script>
<mx:HBox>
<image:ImageBox id="buyTogetherImg" imgData={imageData}/>
<mx:VBox id="textInfo">
<mx:Box id="commonNameBox">
<mx:Label id="commonName" text="{name}">
</mx:Label>
</mx:Box>
<mx:Box id="commonPriceBox">
<mx:Label id="commonPrice" text="{price}">
</mx:Label>
</mx:Box>
</mx:VBox>
and then you do
buyTogetherBox.imageData = yourImageData;
buyTogetherBox.name = "Your Name";
buyTogetherBox.imageData = "Your price";
and yes, remove the unnecessary createGrid() method

flex spark list Drag and drop an item on a spark canvas component

i have a spark list that displays a list of images that represent products. i am trying to implement a drag and drop functionality that allows the user to drag the products he wants to buy from the list to canvas area where he can see the products he choose before buying them. i am using the code below but i cannot figure out what is wrong with it , it seems that i am unable to use the list item as a draginitiator, can any one help please:
private function onMouseDown( event : MouseEvent ) : void
{
var list:List = List(event.currentTarget);
var dragInitiator:Image = Image (list.selectedItem);
var source : DragSource = new DragSource();
source.addData(dragInitiator, "img");
DragManager.doDrag(dragInitiator, source, event);
}
protected function canvas1_dragEnterHandler(event:DragEvent):void
{
DragManager.acceptDragDrop(Canvas(event.currentTarget));
}
protected function canvas1_dragDropHandler(event:DragEvent):void
{
Image(event.dragInitiator).x =
Canvas(event.currentTarget).mouseX;
Image(event.dragInitiator).y =
Canvas(event.currentTarget).mouseY; }
<fx:Model id="categoriesModel" source="Data/Categories.xml"/>
<s:ArrayList id="CategoriesCollection" source="{categoriesModel.Category}"/>
<fx:Model id="productsModel" source="Data/Products.xml"/>
<s:ArrayList id="ProductsCollection" source="{productsModel.Product}" />
</fx:Declarations>
<s:VGroup gap="5" horizontalAlign="center">
<s:HGroup gap="5">
<Components:PROExpressLogo/>
<s:List id="categoryList" scroller="{null}" visible="true"
itemRenderer="Renderers.categoryItemRenderer" width="700" borderAlpha="0"
change="categoryList_changeHandler(event)">
<s:layout>
<s:HorizontalLayout/>
</s:layout>
</s:List>
</s:HGroup>
<s:List id="productList" scroller="{null}" contentBackgroundAlpha="0.4" contentBackgroundColor="0xabcdef"
itemRenderer="Renderers.productItemRenderer" width="880" borderAlpha="0" visible="true" horizontalCenter="0"
dragEnabled="false" mouseDown="onMouseDown(event)"
>
<s:layout>
<s:HorizontalLayout/>
</s:layout>
</s:List>
<s:HGroup gap="20">
<s:Group>
<s:Image id="planImage" width="500" height="300" horizontalCenter="0"
toolTip="Drag your items on your Plan and drop them were you plan to install them"
/>
<mx:Canvas width="500" height="300" backgroundAlpha="0.1"
backgroundColor="#abcdef" borderColor="#abcdef" borderStyle="inset"
contentBackgroundColor="#abcdef" cornerRadius="10"
dragDrop="canvas1_dragDropHandler(event)"
dragEnter="canvas1_dragEnterHandler(event)" dropShadowVisible="true"
horizontalCenter="0"/>
</s:Group>
<s:List id="cart" width="200" height="300"/>
</s:HGroup>
I 'm thinking you need add drag initiator should be the item renderer that you are dragging rather than the entire List control.
Not list.selectedItem that simple object that is not like UIComponent or VisualElement you have to point some ui component like group.

Flex spark list vistual layout control how many items are binded

I have a spark list with custom Itemrenderer.
I use virtuallayout , because I'm binding it with about 500 elements.
I traced the datachange event of the item renderer and I've seen that about 120 items are binded to the list on the first load.
I need to show only 10 items on the stage, so I want to decrease the number of items fetched in the list, is there a property or a function to override to obtain this behaviour?
The code is so simple
<s:List id="thumbnailList" verticalScrollPolicy="off"
useVirtualLayout="true" itemRenderer="ThumbnailItemRenderer" >
<s:layout>
<s:HorizontalLayout gap="10" requestedColumnCount="10" />
</s:layout>
</s:List>
The item renderer
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
autoDrawBackground="false" >
<fx:Script>
override public function set data(value:Object):void{
super.data=value;
if(data !=null){
LoadImg();
}
}
protected function LoadImg():void{
trace(data.pagnum.toString());
var cacheDir:File=null;
cacheDir= Config.DirCache();
var folder:File = new File(cacheDir.nativePath + Config.CATALOG_FOLDER_NAME + Config.selected_catalog_id + "/");
var file:File = new File(folder.nativePath + "/" + data.pagnum.toString() + "_th.jpg");
trace(file.url);
thumbnail.source = file.url;
cacheDir=null;
folder=null;
file=null;
}
</fx:Script>
<s:Image id="thumbnail" top="0" left="0" right="0" bottom="0" scaleMode="letterbox" cacheAsBitmap="true" />
</s:ItemRenderer>
and the binding of the list
thumbnailList.dataProvider= {ArrayCollection with about 480 items}

Flex:How to prompt an alert before navigating to any other page

How to ask user confirmation before highlighting/navigating to another panel/page?
I have few panels in my screen. Each panel has many controls. I would like to prompt a message box(or alert) with Ok and Cancel buttons, and take confirmation whenever user clicks on another panel.
If user clicks on "Ok" button then navigate to another panel/page.
If user clicks on "Cancel" button then remove the alert and focus to the same Panel.
Currently I have implemented this using panel's focus_out event(focusOutHandler(event:FocusEvent)). I click on the button which is in the another panel, now I got alert, but when i clicked on "OK" in the alert , nothing is happening(button click is event is not fired)
Thanks in advance
From the sounds of it you want to react depending on which button on the alert is clicked?
If that is the case, use the in-built close handler in the Alert class.
The Alert class has a static method show, with the following signature:
public static function show(text:String = "", title:String = "", flags:uint = 0x4, parent:Sprite = null, closeHandler:Function = null, iconClass:Class = null, defaultButtonFlag:uint = 0x4, moduleFactory:IFlexModuleFactory = null):Alert
By adding two flags with the pipe operator in the flags argument
Alert.OK || Alert.CANCEL and then adding your close handler in the closeHandler argument, you can inspect which button was clicked and react accordingly.
Something like this:
Alert:
Alert.show("Alert Title","Would you like to proceed?",Alert.OK || Alert.CANCEL,this,onClose)
onClose Function:
private function onClose(event:CloseEvent)
{
if (eventObj.detail==Alert.OK)
{
//proceed
}
else
{
//cancel operation
}
}
As per your comment on James post here i am posting sample, not sure if you are looking for the same: - Hope below code may give you some idea.
<?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:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
private var storeNextFocusID:String = "first";
private var storePreviousFocusID:String = "first";
private function firstFocus():void
{
first.setFocus();
storePreviousFocusID = first.name;
}
private function showFirstTimeAlert(event:MouseEvent):void
{
if(event.currentTarget.name != storePreviousFocusID)
{
Alert.show("Do you want to change Tab?","Alert",Alert.OK|Alert.CANCEL,null,closeHandler)
storeNextFocusID = event.currentTarget.name;
}
}
private function closeHandler(event:CloseEvent):void
{
if(event.detail == Alert.OK)
{
var focusCont:HGroup = mainContainer.getChildByName(storeNextFocusID) as HGroup;
focusCont.setFocus();
storePreviousFocusID = storeNextFocusID;
} else
{
}
}
]]>
</fx:Script>
<s:VGroup id="mainContainer" x="50" y="50" width="400" height="300" creationComplete="firstFocus()">
<s:HGroup id="first" name="first" width="100%" height="100%" click="showFirstTimeAlert(event)">
<mx:TabNavigator width="100%" height="100%">
<mx:VBox label="left">
<mx:Label text="labelPlacement = 'left'" />
</mx:VBox>
<mx:VBox label="right">
<mx:Label text="labelPlacement = 'right'" />
</mx:VBox>
</mx:TabNavigator>
<s:Panel width="100%" height="100%">
</s:Panel>
</s:HGroup>
<s:HGroup id="second" name="second" width="100%" height="100%" click="showFirstTimeAlert(event)">
<mx:TabNavigator width="100%" height="100%">
<mx:VBox label="top">
<mx:Label text="labelPlacement = 'top'" />
</mx:VBox>
<mx:VBox label="bottom">
<mx:Label text="labelPlacement = 'bottom'" />
</mx:VBox>
</mx:TabNavigator>
<s:Panel width="100%" height="100%">
</s:Panel>
</s:HGroup>
</s:VGroup>
</s:Application>

FLEX DataGrid Column Modification

I am new in Flex. I want to display data in attached grid format. I found best way to display in DataGrid. But the CIs column has multiple entries so because of that other columns will duplicate. I want to avoid duplicate data in other columns. Attached screenshot is of excel, i want to achieve same format in Flex. I am using Flex 4.5
Best way I see to do what you want is to create a custom item renderer for the CLS column and have it render as a list control. That way, the CLS item in each row will only take up one row instead of multiple rows.
You can get some idea by following code... you can build logic using below concept for your implementation. Below example is sample not complete according to your requirement: -
<?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:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.core.UIComponent;
import mx.events.AdvancedDataGridEvent;
import mx.events.ListEvent;
[Bindable]
private var dpHierarchy:ArrayCollection= new ArrayCollection
([
{name:"Barbara Jennings", address: "Arizona", contact:999970, orders:["1"]},
{name:"Dana Binn", address: "Arizona", contact:9999130, orders:["2"]},
{name:"Joe Smith", address: "California", contact:9992929, orders:["3"]},
{name:"Alice Treu", address: "California", contact:9999230, orders:["4"]}
]);
private function addOrder():void
{
for(var i:int = 0 ; i < dpHierarchy.length; i++)
{
if(dropDownID.selectedItem.name == dpHierarchy[i].name)
{
var itemUpdated:Array = dpHierarchy[i].orders;
itemUpdated.push(orderNumber.text);
dpHierarchy[i].orders = itemUpdated;
dpHierarchy.itemUpdated(dpHierarchy[i]);
break;
}
}
}
]]>
</fx:Script>
<mx:VBox x="30" y="30" width="450" height="400">
<s:HGroup>
<s:Button label="Add Order" click="addOrder()"/>
<s:DropDownList id="dropDownID" dataProvider="{dpHierarchy}" labelField="name" selectedIndex="0"/>
<s:TextInput id="orderNumber" width="100"/>
</s:HGroup>
<mx:AdvancedDataGrid id="myADG"
dataProvider="{dpHierarchy}"
variableRowHeight="true" wordWrap="true">
<mx:columns>
<mx:AdvancedDataGridColumn dataField="name" headerText="Name"/>
<mx:AdvancedDataGridColumn dataField="address" headerText="Address"/>
<mx:AdvancedDataGridColumn dataField="contact" headerText="Contact"/>
<mx:AdvancedDataGridColumn dataField="orders" headerText="Orders" itemRenderer="OrderItemRenderer"/>
</mx:columns>
</mx:AdvancedDataGrid>
</mx:VBox>
</s:Application>
Item Reenderer Name: - OrderItemRenderer
<?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" width="90%" height="90%">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection();
override public function set data(value:Object):void
{
super.data = value;
initDG = new ArrayCollection(value.orders)
}
]]>
</fx:Script>
<mx:DataGrid id="dataGrid" dataProvider="{initDG}" headerHeight="0" rowCount="{initDG.length}"/>
</s:MXAdvancedDataGridItemRenderer>