Strange behaviour of scrolling in flex mobile - actionscript-3

working on flex mobile list. list is represented using itemrenderer.
here is the itemrendeerer..
<s:Image id="img" x="30" y="50"/>
<s:Label id="nameLbl" width="100%" height="100%" text="Label" textAlign="center" verticalAlign="middle"/>
<s:Button id="checkMarkLabel" label="+" height="100%" />
on selected::
protected function onClicked(event:MouseEvent):void
{
if(checkMarkLabel.label =="✓")
{
checkMarkLabel.label = "+";
}
else if(checkMarkLabel.label == "+" )
{
checkMarkLabel.label = "✓";
trace("id::"+event.currentTarget.data.id)
//FlexGlobals.topLevelApplication.selectedId = event.currentTarget.data.id;
}
}
the image gives you the clear picture.
after selecting some items in the list,if i scroll the list,the checked items gets unchecked and the unchecked items gets checked.any answer is appreciable..

Flex don't create renderer for each item in list instead Flex create few renderers (in your case 6) and reuse them.
You must save data about clicked list items (maybe use some singleton), and then you must override set data method in renderer class (in this method you get list item for renderer), then you figure out clicked this item or not and set to checkMarkLabel corresponded symbol.

On the list you can set the property "useVirtualLayout" to false. This will generate an unique itemrenderer for each item in the list. This is also what Anton was talking about.
This is however less resource friendly. If your list get's really large it will take up more memory.
You should work with states that are already made use of by lists in combination with itemrenderers.
Example itemrenderer:
<fx:Script>
<![CDATA[
protected function marker_clickHandler(event:MouseEvent):void {
marker.label = marker.label == "V" ? "+" : "V";
}
]]>
</fx:Script>
<s:states>
<s:State name="normal"/>
<s:State name="selected"/>
</s:states>
<s:Button label.selected="V" label.normal="+"/>
<s:Button y="10" id="marker" click="marker_clickHandler(event)" label="+"/>
If you were to use this as an itemrenderer, the button utilizing states will update as expected, but like Anton mentioned, the ones marked manually onClick will not get updated as expected.

This answer builds on Robin van den Bogaard's answer.
Assuming your current dataProvider has objects that look like this:
public class MyData {
[Bindable]
private var imgUrl:String;
[Bindable]
private var name:String;
}
Add a new field to it:
[Bindable]
private var chosen:Boolean;
(If you don't have [Bindable], add it to enable data binding on the data items.)
Then your itemRenderer can look like this, automatically updating as you scroll:
<fx:Script>
<![CDATA[
protected function marker_clickHandler(event:MouseEvent):void {
data.chosen = !data.chosen;
}
]]>
</fx:Script>
<s:states>
<s:State name="normal"/>
<s:State name="selected"/>
</s:states>
<s:Image id="img" x="30" y="50" source="{data.imgUrl}" />
<s:Label id="nameLbl" width="100%" height="100%" text="Label" textAlign="center" verticalAlign="middle" text="{data.name}" />
<s:Button id="checkMarkLabel" label="{data.chosen ? '✓' : '+'}" height="100%" click="marker_clickHandler(event)" />

Related

Actionscript 3 setStyle is not a function

I am trying to style a Flex 4 GridItem using actionscript, I have tried the following:
<mx:VBox
height="878" width="1920"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:s="library://ns.adobe.com/flex/spark" xmlns:local="*" creationComplete="addStyles()">
<mx:Script>
<![CDATA[
public var selectedLot:String = "";
private function addStyles():void
{
testBorder.setStyle("borderThickness", "3");
}
but I get the following error:
setStyle is not a function.
Am I missing something?
The GridItem is inside a repeater.
Here is my GridItem:
<mx:GridItem id="testBorder" width="101" height="52.25" horizontalAlign="center" verticalAlign="middle" borderStyle="solid" borderColor="gray">
<mx:Image source="assets/ruler-icon.png" />
<s:Label text="{r.currentItem.sqft}" fontSize="10" color="#808080" fontFamily="Helvetica" />
</mx:GridItem>
When using a repeater the GridItem's id will not be the same. To access any item inside a repeater you have to specify an index which is correspondent to the repeated item.
Example: Array consists of ["Audi", "BMW"], we set this array to your repeater's dataProvider, then to access "Audi"'s grid item and set its style, we have to use:
testBorder[0].setStyle("borderThickness", "3");
Additionally, an important point to consider, the VBox "creationComplete" can be executed before the repeater is fully built, therefore, the best place to call your function "addStyles" is in the repeater's "repeatEnd" event i.e (repeatEnd="setTransactionPropertyType()").
Hope this helps,
Goodluck.

Custom external itemRenderer is receiving null objects from dataProvider

I have a custom external itemRenderer which I use to display items in a mx:List. The dataProvider is an Array that contains 4 attributes per element. It seems as if the itemRenderer is, in fact, getting the Array because it displays 4 items(the amount of items in the Array) but the items are displayed as "[object Object]".
Here is my itemRenderer...
<mx:Metadata>
[Event(type="classes.events.RemoveEntryEvent", name="removeProject")]
</mx:Metadata>
<mx:Script>
<![CDATA[
import classes.events.RemoveEntryEvent;
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.events.FlexEvent;
override public function set data (value:Object):void{
super.data = value;
//Alert.show(value.toString());
}
public function button_clickHandler():void {
var alertListener:Function = function(closeEvent:CloseEvent):void{
if (closeEvent.detail == Alert.YES){
//dispatchEvent(new RemoveEntryEvent(RemoveEntryEvent.REMOVE_PROJECT, true, false, data));
}
}
var myAlert:Alert = Alert.show("Are you sure you want to remove yourself from this project?",
"Remove Project",
(Alert.YES | Alert.CANCEL),
null, alertListener);
myAlert;
}
private function text_clickHandler():void{
Alert.show("inside text_clickHandler()");
}
]]>
</mx:Script>
<!-- The mx:Text should display a hand maybe when rolledOver: !buttonMode, -->
<mx:Text id="text" width="85%" text="{data}" fontThickness="5" click="text_clickHandler()"/>
<mx:Button id="removeButton" label="Remove" fontSize="9" width="63" verticalCenter="0" fontWeight="normal" x="329"
height="17" click="button_clickHandler()"></mx:Button>
</mx:Canvas>
When I step through the set data function, the 'value:Object' is null! But again, it is displaying the correct amount of items.
Here is my mxml code in which my mx:List is contained...
<mx:TitleWindow y="10" width="550" height="342" layout="absolute" title="LIST OF PROJECTS" cornerRadius="4" id="listOfProjects_panel" horizontalCenter="0">
<mx:List alternatingItemColors="{altColors}" x="65.5" y="30" width="399" height="232" backgroundColor="#F8F8F8" fontSize="12" dataProvider="{xmlSimpleArray}"
id="list_of_projects_master" initialize="listInitializer()" useRollOver="false" selectable="false">
</mx:List>
<mx:Button y="270" label="Refresh List" width="130" x="334.5" id="auth_btn_master0" fontWeight="normal"/>
<mx:Label x="65.5" y="10" text="Click To Select A Project:" fontWeight="bold"/>
</mx:TitleWindow>
Here is the initializer in my mx:Script...
private function listInitializer():void{
//list_of_projects_master.dataProvider = xmlSimpleArray;
list_of_projects_master.itemRenderer = new ClassFactory(ProjectListRenderer);
list_of_projects_master.addEventListener(RemoveEntryEvent.REMOVE_PROJECT, updateXML);
}
If anymore information is needed to assess the issue, please let me know
change the below line in itemrenderer
<mx:Text id="text" width="85%" text="{data}" fontThickness="5" click="text_clickHandler()"/>
shoul be like
<mx:Text id="text" width="85%" text="{data.labelfieldname}" fontThickness="5" click="text_clickHandler()"/>
hope this helps.

Items in DataGrid not initialized as expected

I seem to have a problem of items not being created as expected, resulting in event-listeners not being fired.
I am using a DataGrid column of checkboxes as seen here:
<mx:DataGrid id="gridComponents" height="100%">
<mx:columns>
<fwctrl:DataGridCheckBoxColumn id="colChkBox" width="20" selectionChanged="onGridChbBoxChange(event)" />
<mx:DataGridColumn headerText="Components" dataField="name" width="250"/>
</mx:columns>
</mx:DataGrid>
(fwctrl is the namespace of an internal library.)
And here is what the mxml of fwctrl:DataGridCheckBoxColumn looks like:
<mx:DataGridColumn xmlns:mx="http://www.adobe.com/2006/mxml" resizable="false" xmlns:grid="fwctrl.grid.*" xmlns:CheckBoxColumn="fwctrl.grid.CheckBoxColumn.*">
<mx:Metadata>
[Event(name="selectionChanged", type="fwctrl.grid.CheckBoxColumn.DataColumnCheckBoxEvent")]
</mx:Metadata>
<mx:Script>
<![CDATA[
...
]]>
</mx:Script>
<mx:headerRenderer>
<mx:Component>
<CheckBoxColumn:CheckBoxHeaderRenderer textAlign="center" click="checkboxheaderrenderer1_clickHandler(event)">
<mx:Script>
...
</mx:Script>
</CheckBoxColumn:CheckBoxHeaderRenderer>
</mx:Component>
</mx:headerRenderer>
<mx:itemRenderer>
<mx:Component>
<mx:Box horizontalAlign="center"
verticalAlign="middle" enabled="{outerDocument.isEnabled}">
<mx:Script>
<![CDATA[
...
protected function checkBox_initializeHandler(event:FlexEvent):void
{
trace("init checkbox");
}
]]>
</mx:Script>
<mx:CheckBox id="checkBox" click="onCheckBoxClick()" change="onChange(event)" initialize="checkBox_initializeHandler(event)"/>
</mx:Box>
</mx:Component>
</mx:itemRenderer>
CheckBoxHeaderRenderer is a class that inherits from checkbox.
using the mxml above I bind an ArrayCollection to the data provide by doing: gridComponents.dataProvider = coll;
Having the checkBox_initializeHandler event bound, I expect to see a message printed for each element in my collection.
In reality, the message will only be displayed for element that don't "fall off the grid", i.e. if there is a scroll bar (due to a lot of items being rendered), the items that are below the bottom of the grid (i.e. the ones that need to be scrolled to) will not print a message.
This also means that they are not created correctly and that the click="onCheckBoxClick()" is not hooked correctly and that onCheckBoxClick() does not get triggered.
Why is this happening and how can I fix this?
In Flex, itemRenderers aren't created on a one-to-one basis with your underlying data collection. You only get enough instances to display one screen's worth of data, and those instances get reused as you scroll.
To handle this in your code, refactor so that your click handler in the itemRenderer updates a property in your dataCollection (e.g. data.foo = true;).

How to change the visibility of components from different states in Flex 4

My goal is to change the visibility of a component from another component which is in another state. I been reading about the event but I can Flex it to work, I get this TypeError: Error # 1009: Can not access a property or method of a null object reference.
<<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.FlexEvent;
protected function buttonChange_clickHandler(event:MouseEvent):void
{
Tab.selectedIndex=1;
border.visible=true;
border.setStyle("backgroundColor",'#8000FF');
}
]]>
</fx:Script>
<mx:TabNavigator x="197.7" y="147.35" width="514" id="Tab" height="335">
<s:NavigatorContent label="State 1" width="100%" height="100%">
<s:Button x="65" y="103" id="buttonChange" label="Change state" click="buttonChange_clickHandler(event)" />
</s:NavigatorContent>
<s:NavigatorContent label="State2" id="state2" width="100%" height="100%">
<s:BorderContainer x="191" y="37" width="249" height="223" visible="false" cornerRadius="20" borderWeight="5" id="border">
</s:BorderContainer>
</s:NavigatorContent>
</mx:TabNavigator>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
The error occurs because your BorderContainer is not "created" when the tab navigator change the index. There are two fast ways to resolve that:
1) Use callLater to ensure that the border will be created when the tab change:
protected function buttonChange_clickHandler(event:MouseEvent):void
{
Tab.selectedIndex=1;
callLater(turnVisible);
}
private function turnVisible():void{
border.visible=true;
border.setStyle("backgroundColor",'#8000FF');
}
2) Or set the creationPolicy to "all" of the second </s:NavigatorContent>. That way will increase the startup time of the application:
<s:NavigatorContent label="State2" id="state2" width="100%" height="100%" creationPolicy="all">

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.