How to detect whether a list is scrolling or not? - apache-flex

Is there any way to detect whether a list is scrolling or not,likelist.isScrolling

So, #Khaled showed a way to do it with the MX component. If you are using the Spark component, that event doesn't work. Instead, you can listen to changes on myList.scroller.viewport.verticalScrollPosition or horizontalScrollPosition.
<fx:Declarations>
<fx:int id="scrollingCount" />
</fx:Declarations>
<s:initialize>
BindingUtils.bindSetter(function(x:*):void { scrollingCount++; }, myList.scroller.viewport, "verticalScrollPosition");
</s:initialize>
<s:VGroup>
<s:Label text="Scrolling: {scrollingCount}" />
<s:List id="myList" height="200" dataProvider="{myData}" />
</s:VGroup>
In neither of these cases do you get to know when the list stops getting scrolled (I'm not sure if you want it or not). You might have to set a timer and any time the timer goes off without any scrolling events, you are no longer scrolling?
Unfortunately, you haven't explained what you are trying to accomplish, wo we can't adequately answer your question.

Or you can do somme thing like this in a list itemrenderer :
import spark.components.List;
[Bindable]
private var calcWidth:Number=195;
private var listVerticalScroll:Boolean;
private var listHorizontalScroll:Boolean;
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
var ownerVerticalScroll:Boolean=List(owner).scroller.verticalScrollBar.visible;
var ownerHorizontalScroll:Boolean=List(owner).scroller.horizontalScrollBar.visible;
if(ownerVerticalScroll!=listVerticalScroll){
listVerticalScroll=ownerVerticalScroll;
scrollBarChange()
}
super.updateDisplayList(unscaledWidth,unscaledHeight);
}
private function scrollBarChange():void {
if(listVerticalScroll){
var newWidth:Number=195-(listVerticalScroll?15:0);
calcWidth=newWidth;
}
}

you can use the ScrollEvent.SCROLL :
import mx.events.ScrollEvent
myList.addEventListener(ScrollEvent.SCROLL, scrollHandler);
function scrollHandler(e:ScrollEvent):void
{
//myList is scrolling
}

Or you can do it like this for spark component!
http://blog.flexexamples.com/2009/05/31/detecting-when-the-vertical-scroll-bar-is-scrolled-on-a-spark-list-control-in-flex-4/ -->
<fx:Script>
<![CDATA[
import spark.components.VScrollBar;
private function init():void {
list.scroller.verticalScrollBar.addEventListener(Event.CHANGE, list_verticalScrollBar_change);
}
private function list_verticalScrollBar_change(evt:Event):void {
var vsb:VScrollBar = evt.currentTarget as VScrollBar;
var obj:Object = {};
obj.type = evt.type;
obj.val = vsb.value;
obj.max = vsb.maximum;
arrColl.addItem(obj);
callLater(dgScroll);
}
private function dgScroll():void {
dataGrid.verticalScrollPosition = dataGrid.maxVerticalScrollPosition;
}
]]>
</fx:Script>
<fx:Declarations>
<mx:ArrayCollection id="arrColl" />
</fx:Declarations>
<s:HGroup horizontalCenter="0" verticalCenter="0">
<s:List id="list"
creationComplete="init();">
<s:layout>
<s:VerticalLayout gap="0"
horizontalAlign="contentJustify"
requestedRowCount="4" />
</s:layout>
<s:dataProvider>
<s:ArrayList>
<fx:String>The</fx:String>
<fx:String>Quick</fx:String>
<fx:String>Brown</fx:String>
<fx:String>Fox</fx:String>
<fx:String>Jumps</fx:String>
<fx:String>Over</fx:String>
<fx:String>The</fx:String>
<fx:String>Lazy</fx:String>
<fx:String>Dog</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:List>
<mx:DataGrid id="dataGrid"
dataProvider="{arrColl}"
width="200"
verticalScrollPolicy="on">
<mx:columns>
<mx:DataGridColumn dataField="type" />
<mx:DataGridColumn dataField="val" />
<mx:DataGridColumn dataField="max" />
</mx:columns>
</mx:DataGrid>
</s:HGroup>
</s:Application>

Related

How to set different font color in combobox items in flex

I have a ComboBox in Flex which is listing like this:
A-B-C-D-E-F
A-B-C-D-E-F-*
A-B-C-D-E-F-G-*
A-B-C-D-E-F-*
I want to make the * appear red. Could anyone help me regarding this?
Hopefully self-explaining:
<s:ComboBox itemRendererFunction="getItemRenderer"
dataProvider="{new ArrayList(['A-B-C-D-E-F', 'A-B-C-D-E-F-', 'A-B-C-D-E-F-G-', 'A-B-C-D-E-F-'])}"/>
<fx:Declarations>
<fx:Component className="RedItemRenderer">
<s:ItemRenderer>
<s:HGroup verticalAlign="middle">
<s:Label text="{data}" color="red" paddingLeft="3" paddingRight="3" paddingTop="5" paddingBottom="5"/>
<s:Image source="#Embed(source='warning.png')"/>
</s:HGroup>
</s:ItemRenderer>
</fx:Component>
</fx:Declarations>
<fx:Script><![CDATA[
import mx.collections.ArrayList;
import spark.skins.spark.DefaultItemRenderer;
private function getItemRenderer(item:Object):IFactory
{
var s:String = item as String;
if (s.charAt(s.length-1) == '-')
return new ClassFactory(RedItemRenderer);
else
return new ClassFactory(DefaultItemRenderer);
}
]]></fx:Script>
This is how it looks like:

Can <fx:Script> be declared outside and inside itemrenderer?

I am declaring a variable outside the itemRenderer fx:Script body. However when I am setting it as such in my itemRenderer:
test_Var = data.#field_value;
It is giving an error "Access of undefined property test_Var"
Can I have 2 bodies, one inside the itemrenderer and the usual outside one?
public var test_Var:Number = new Number();
public function useVariableValue():void{
// I will use the variable value in this function..
}
]]>
</fx:Script>
<mx:DataGrid id="myDG" rowCount="8" creationComplete="myDG_creationCompleteHandler(event)" resizableColumns="false" height="234">
<mx:columns>
<mx:DataGridColumn headerRenderer="renderers.datagridHeaderRenderer" dataField="#field_label" headerText="Header1" width="130" />
<mx:DataGridColumn dataField="#field_value" headerText="Header2" itemRenderer="renderers.labelItemRenderer1" />
<mx:DataGridColumn headerText="Header3">
<mx:itemRenderer>
<fx:Component>
<mx:Canvas dataChange="canvas1_dataChangeHandler(event)">
<s:Button horizontalCenter="1" id="button" click="onClick(event)" label="View"/>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.FlexEvent;
protected function canvas1_dataChangeHandler(event:FlexEvent):void
{
if(data.#field_visibility == "true"){
this.button.visible = true;
}
else{
this.button.visible = false;
}
}
private function onClick(evt:Event):void
{
test_Var = data.#field_value;
}
]]>
</fx:Script>
</mx:Canvas>
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>*
fx:Component defines a totally new scope. You can only access properties in your initial scope by using the outerDocument keyword.
In your case change it to this:
private function onClick(evt:Event):void
{
outerDocument.test_Var = data.#field_value;
}
For more information read (see the section on outerDocument):
http://www.adobe.com/devnet/flex/articles/itemrenderers_pt1.html

Trying to get global y coordinate of datagrid selecteditem

Here's the situation:
I have a populated datagrid and I want to move a form to be inline (same y position) with the datagrid's selectedItem. I cannot rely on a mouseClick event because the selected item may change with a keyboard event. The datagrid does not have an itemRenderer, just plain old dataField.
Anyone done this before?
Here's some stubbed out example code for all those interested based on Jacob's answer.
<?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[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import mx.events.ListEvent;
import mx.formatters.DateFormatter;
[Bindable] public var ac_POitems:ArrayCollection = new ArrayCollection();
[Bindable] public var selectedY:int;
protected function dg_POitems_creationCompleteHandler(event:FlexEvent):void
{
//TODO
}
protected function submit_clickHandler(event:MouseEvent):void
{
//TODO
}
protected function format_sqlite_date(item:Object, col:DataGridColumn):String
{
var df:DateFormatter = new DateFormatter();
df.formatString = "MM/DD/YYYY";
var value:Object = item[col.dataField];
return df.format(value);
}
protected function dg_POitems_changeHandler(event:ListEvent):void
{
trace(event.itemRenderer.y);
selectedY = event.itemRenderer.y;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:VBox width="100%" height="100%" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
<mx:DataGrid id="dg_POitems" dataProvider="{ac_POitems}" creationComplete="dg_POitems_creationCompleteHandler(event)"
editable="true" height="100%" change="dg_POitems_changeHandler(event)">
<mx:columns>
<mx:DataGridColumn headerText="Consumer" dataField="consumer" editable="false"/>
<mx:DataGridColumn headerText="Description" dataField="description" width="300" editable="false"/>
<mx:DataGridColumn headerText="Amount" dataField="item_cost" editable="false" width="55"/>
<mx:DataGridColumn headerText="Service Date" dataField="service_date" labelFunction="format_sqlite_date"/>
<mx:DataGridColumn headerText="Invoice Date" dataField="invoice_date" labelFunction="format_sqlite_date"/>
<mx:DataGridColumn headerText="Paid Date" dataField="payment_received" labelFunction="format_sqlite_date"/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
<mx:Form id="form_POItemDateEditor" label="{dg_POitems.selectedItem.consumer}" x="{dg_POitems.x + dg_POitems.width + 10}"
y="{selectedY + 10}" visible="{dg_POitems.selectedItem}" borderColor="#ffffff">
<s:Label text="edit {dg_POitems.selectedItem.consumer}" width="100%" textAlign="center" verticalAlign="middle" fontWeight="bold" textDecoration="underline"/>
<mx:FormItem label="Service Date">
<mx:DateField id="service_date"/>
</mx:FormItem>
<mx:FormItem label="Invoie Date">
<mx:DateField id="invoice_date"/>
</mx:FormItem>
<mx:FormItem label="Paid Date">
<mx:DateField id="payment_received"/>
</mx:FormItem>
<mx:FormItem>
<s:Button id="submit" label="Submit" click="submit_clickHandler(event)"/>
</mx:FormItem>
</mx:Form>
</s:Application>
This should help you get started:
<fx:Script>
<![CDATA[
import mx.events.ListEvent;
protected function datagrid1_changeHandler(event:ListEvent):void
{
trace(event.itemRenderer.y);
}
]]>
</fx:Script>
<mx:DataGrid dataProvider="{steps}" change="datagrid1_changeHandler(event)" >
....
Edit Showing listener for spark:List valueCommit Event.
protected function valueCommitHandler(event:FlexEvent):void
{
trace(event.currentTarget.layout.getElementBounds(list.selectedIndex));
}
Have a look at DisplayObject's localToGlobal function. It will allow you to convert the ItemRenderer's 'y' position (that is with respect to the parent container, probably a List) to a global 'y' position (with respect to the Stage).
globalToLocal will do the opposite.
You'll have to do some additional calculations from here on, but those will depend on what your application display hierarchy looks like, so I can't be more specific than that.
You can find full code for exactly what you want to do right here http://flexdiary.blogspot.com/2009/11/flex-template-component.html

Selection in Flex Datagrid does not pass the valueObject to selectionChangeHandler function

I have a TabNavigator, and each tab is a Module. One of the modules is labelled Units and the full code of the module is posted in this post.
There are several problems:
1) Forms are not populated with data from the datagrid selection.
2) Selecting a row and clicking delete gives the very-common error: TypeError: Error #1009: Cannot access a property or method of a null object reference.
A trace on the valueObject unit within the selectionChangeHandler function gives NULL. Why?
Note: In other modules (other tabs of the TabNavigator), I have DropDownLists populated with units. This means that the valueObject Unit is defined in the other modules. However, valueObjects should be private to modules, and not shared. I am unsure where the problem comes.
Full module code:
<?xml version="1.0" encoding="utf-8"?>
<s:Module xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:unitservice="services.unitservice.*"
xmlns:valueObjects="valueObjects.*"
width="724"
height="674">
<fx:Style source="assets/CAaNDFlex.css"/>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.FlexEvent;
import mx.rpc.events.ResultEvent;
import spark.events.GridSelectionEvent;
protected function unitsDg_creationCompleteHandler(event:FlexEvent):void
{
getUnitsResult.token=unitservice.getUnits();
}
protected function addBtn_clickHandler(event:MouseEvent):void
{
currentState="unitsAdd";
unit=new Unit();
}
protected function unitsDg_selectionChangeHandler(event:GridSelectionEvent):void
{
trace(event.currentTarget.selectedItem); //Unit object detected
trace(event.currentTarget.selectedItem as Unit); //NULL
trace(unit); // unit is NULL. Why?
currentState="unitsDetails";
}
protected function button_clickHandler(event:MouseEvent):void
{
trace(unit); // unit is NULL. Why?
unit.unitName=unitNameTextInput.text;
if (unit.unitID == 0)
{
createUnitResult.token=unitservice.createUnit(unit);
}
else
{
updateUnitResult.token=unitservice.updateUnit(unit);
}
}
protected function updateBtn_clickHandler(event:MouseEvent):void
{
currentState="unitsUpdate";
}
protected function createUnitResult_resultHandler(event:ResultEvent):void
{
currentState="unitsDetails";
unit.unitID=event.result as int;
unitsDg.dataProvider.addItem(unit);
unitsDg.setSelectedIndex(unitsDg.dataProvider.getItemIndex(unit));
unitsDg.ensureCellIsVisible(unitsDg.selectedIndex);
}
protected function deleteBtn_clickHandler(event:MouseEvent):void
{
deleteUnitResult.token = unitservice.deleteUnit(unit.unitID);
}
protected function deleteUnitResult_resultHandler(event:ResultEvent):void
{
unitsDg.dataProvider.removeItemAt(unitsDg.selectedIndex);
currentState="units";
}
]]>
</fx:Script>
<s:states>
<s:State name="units"/>
<s:State name="unitsDetails"/>
<s:State name="unitsAdd"/>
<s:State name="unitsUpdate"/>
</s:states>
<fx:Declarations>
<s:CallResponder id="getUnitsResult"
result="unit = getUnitsResult.lastResult as Unit"/>
<unitservice:UnitService id="unitservice"
fault="Alert.show(event.fault.faultString + '\n' + event.fault.faultDetail)"
showBusyCursor="true"/>
<valueObjects:Unit id="unit" />
<s:CallResponder id="createUnitResult"
result="createUnitResult_resultHandler(event)"/>
<s:CallResponder id="updateUnitResult"/>
<s:CallResponder id="deleteUnitResult" result="deleteUnitResult_resultHandler(event)"/>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Binding destination="unit" source="unitsDg.selectedItem as Unit"/>
<s:DataGrid id="unitsDg" x="10" y="37"
creationComplete="unitsDg_creationCompleteHandler(event)" requestedRowCount="4"
selectionChange="unitsDg_selectionChangeHandler(event)">
<s:columns>
<s:ArrayList>
<s:GridColumn dataField="unitName"
headerText="unitName">
</s:GridColumn>
<s:GridColumn dataField="unitID"
headerText="unitID">
</s:GridColumn>
</s:ArrayList>
</s:columns>
<s:typicalItem>
<fx:Object unitID="unitID1"
unitName="unitName1">
</fx:Object>
</s:typicalItem>
<s:AsyncListView list="{getUnitsResult.lastResult}"/>
</s:DataGrid>
<s:Button id="addBtn" x="10" y="0" label="Add" click="addBtn_clickHandler(event)"
styleName="actionButton"/>
<s:Form includeIn="unitsAdd,unitsUpdate"
x="10"
y="176"
defaultButton="{button}">
<s:FormItem label="unitName">
<s:TextInput id="unitNameTextInput"
text="{unit.unitName}"/>
</s:FormItem>
<s:Button id="button"
label="Add"
click="button_clickHandler(event)"
label.unitsUpdate="Update"/>
</s:Form>
<s:Button id="updateBtn" x="138" y="0" label="Update" click="updateBtn_clickHandler(event)"/>
<s:Button id="deleteBtn" x="266" y="0" label="Delete" click="deleteBtn_clickHandler(event)"/>
<s:Form includeIn="unitsDetails" x="10" y="176">
<s:FormItem label="unitName">
<s:Label id="unitNameLabel" text="{unit.unitName}"/>
</s:FormItem>
</s:Form>
</s:Module>
The selectedObject is not successfully casting to Unit, which means it probably wasn't Unit or a subclass prior to the cast. Casting it to Unit won't make it a Unit unless it was one before.

flex 3's datagrid won't stretch

I wrote very simple code to understand how columnstretch and calllater work but I couldn't get resizeGrid function worked. What is going on here?
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var denemelist:ArrayCollection;
private function calculateHeight(l:int):Number{
return deneme.measureHeightOfItems(0, l) + deneme.headerHeight;
}
public function resizeGrid():void{
if(denemelist && deneme)
deneme.height = calculateHeight(denemelist.length);
}
public function preinit():void {
denemelist = new ArrayCollection([
{former:"sdfad", latter:"sdfgs"},
{former:"sdfgsd", latter:"sdfgsfd"}
]);
}
public function test():void {
denemelist.addItem({former:"sdfgsdf", latter:"sdfgdsgf"});
}
]]>
</mx:Script>
<mx:VBox width="100%" height="500">
<mx:DataGrid
width="100%"
resizeEffect="Resize"
horizontalScrollPolicy="off" verticalScrollPolicy="off"
id="deneme"
variableRowHeight="true"
editable="false"
dataProvider="{denemelist}"
styleName="phrDataGrid"
columnStretch="callLater(resizeGrid)">
<mx:columns>
<mx:DataGridColumn dataField="former" headerText="former"/>
<mx:DataGridColumn dataField="latter" headerText="latter"/>
</mx:columns>
</mx:DataGrid>
<mx:Button label="deneme1" click="test()" />
</mx:VBox>
I don't think the datagrid has been updated yet at the time that you're calling the function. But you might try leaving off the height of the dg and then just setting the rowCount to the number of items in the list.
HTH;
Amy

Resources