Flex components initialization and creation order - apache-flex

While trying to sort out a problem with loading components and firing events based on that, I came across a question for which I could not find an answer online.
Following is a sample of reference code
<s:WindowedApplication>
<s:states>
<s:State name="login"/>
<s:State name="data"/>
</s:states>
<s:VGroup id="login" includeIn="login">
<s:HGroup id="loginHGroup">
</s:HGroup>
</s:VGroup>
<s:VGroup id="data" includeIn="data">
<s:VGroup id="v1">
<s:HGroup id="h11">
</s:HGroup>
<s:HGroup id="h12">
</s:HGroup>
</s:VGroup>
<s:VGroup id="v2">
<s:HGroup id="h21">
</s:HGroup>
</s:VGroup>
</s:VGroup>
</s:WindowedApplication >
Now if I want to fire an event after the last UI component 'data' state gets created - which element do I fire it off from? Will HGroup h12 get created first or h21?
What is the flow of element creation in Flex - does it follow DOM schematics or is there some other mechanism?
[Remember that I cannot fire creationComplete at WindowedAPplication level as that is going to get fired when the login state is created].

Always the outer component is the last one to fire the creationcomplete event, so, you can add creation complete event listener on the application, or You can even add the applicationComplete event on the application which occurs after the creation complete.

Related

event after list finish rendering?

I'm using a spark list to render data which I get from a web service.
is there an event which fires after the list has finished rendering all the data ?
I want to show a loading image to the user until the list finishes.
Thanks
I believe the event you are looking for is updateComplete.
If I were you, I'd create 2 states: "loading" and "normal". The initial state is "loading" by setting currentState by default, during which it shows a loader. After that, I would have a check on the data property that you surely have somewhere. You can bind that to check if it's not null and change the state accordingly. Here's an example:
<s:Group currentState="{someDataFromService?'normal':'loading'}">
<s:states>
<s:State name="normal" />
<s:State name="loading" />
</s:states>
<custom:SomeLoadingComponent includeIn="loading" />
<s:List id="list" dataProvider="{someDataFromService}" enabled.loading="false" />
</s:Group>
I left out the data property since I'm sure you can figure that part out on your own.

ArrayCollection getItemAt

I created an Item Renderer for the Flex Spark List Component.
The problem is that this code will not work:
<s:Label left="10" right="10" top="10" bottom="10" fontSize="13" text="{data.getItemAt(1).toString()}"
textAlign="left" verticalAlign="middle"/>
While this code will:
<s:Label left="10" right="10" top="10" bottom="10" fontSize="13" text="{data[1].toString}"
textAlign="left" verticalAlign="middle"/>
I can't use the later code because of binding issues.
Does anyone have any idea on what I'm doing wrong?
As #J_A_X' comment stated, these are two completely different things.
{data.getItemAt(1)...
Refers to an ArrayCollection, or possibly some other collection.
{data[1]...
Refers to an Array.
Attempting to treat an array as an array collection will not get you very far. I would recommend ensuring that the each item in your list is actually an ArrayCollection. Alternatively, I would more strongly support replacing them with value objects, and binding to a 'title','text', or whatever property more correctly defines the text you wish to display.
{data.title}

How to pass parameters to decoratorClass in MobileIconItemRenderer?

How to pass parameters to decoratorClass in MobileIconItemRenderer ? I have a custom control to display a metric (get from data collection), this control will be used as decoretorClass, my problem is that I couldn't set the metric parameter on my custom control, you can find below a sample code. How to do to pass values to a instance for my custom component ? Exist any way, or I have to re-make the MobileIconItemRenderer class ?
<s:List id="dealList" top="0" bottom="0" left="0" right="0" width="100%" height="100%"
dataProvider="{dealService.lastResult.Response.Items.Item}" >
<s:itemRenderer>
<fx:Component>
<s:MobileIconItemRenderer label="{data.Metric_Name}" messageField="Customer" decoratorClass="{MetricViewer}">
<fx:Script>
<![CDATA[
import mobile.ui.component.mxml.MetricViewer;
]]>
</fx:Script>
</s:MobileIconItemRenderer>
</fx:Component>
</s:itemRenderer>
Here is one example. However, it suggest to set a different decorator class based on the data.
Here is a different example, that seems to accomplish the same thing but does not use a decorator to do so.
There does not seem to be a documented API that you can use to access the instance of the decorator, but I bet if you drill into the code there is a way.

How to access variable in parent component from child component?

I have a public variable set within fx:Script tags in a parent component that I'd like to access directly from a child component. How can I do this? I don't want to pass the variable to the child component (I know how to do this and am currently using this approach). Following is a simplified version of the mxml:
Note: SimpleComp is an HBox with a couple of lists.
<mx:Accordion>
<comp:SimpleComp/>
</mx:Accordion>
You could use event to communicate, in that sense Signals can be a pretty good approach
http://www.peterelst.com/blog/2010/01/22/as3-signals-the-best-thing-since-sliced-bread/
In your desire to directly access a public variable in a different class arbitrarily without employing another design pattern you're sort of breaking encapsulation principles. If it's a one time thing, you can just define your child component to take a reference to its parent on instantiation.
If you need to do this a lot, there is an excellent implementation of Apple's NSNotificationCenter in AS3 defined here: http://www.archer-group.com/development/mimicking-cocoas-nsnotificationcenter-in-actionscript-3 that will allow your objects to communicate with each other more robustly and appropriately.
You can do the following in the code of your SimpleComp component:
var parent:Accordion = this.parent as Accordion;
to have an access to all parent's public fields.
But that is not good style, as already mentioned above.
Mb you should consider some event dispatching mechanism or using mvc frameworks like PureMVC.
Hmm not sure what you are after, but maybe outerDocument is what you are after
e.g.
<mx:DataGrid>
<mx:columns>
<mx:DataGridColumn>
<mx:itemRenderer>
<fx:Component>
<s:MXDataGridItemRenderer autoDrawBackground="false">
<fx:Script>
<![CDATA[
public function action():void
{
trace(outerDocument.fooBar);
}
]]>
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="hovered" />
<s:State name="selected" />
</s:states>
</s:MXDataGridItemRenderer>
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>

Recreating/resetting views with Flex ViewStack

I'm writing an Adobe AIR application using a ViewStack for the different application states. Is there a way to make sure that each view component is created/destroyed each time it is shown/hidden?
For instance, if I have a TextInput in a view, I want it to reset to its initial state each time I change to that view, rather than having previously entered text. Or, if I have a Timer, I want it to be destroyed when I leave the view so that it doesn't keep running when I'm in an unrelated part of the application. I know that I can manually initialize/destroy everything on the show() and hide() events, but is there an easier way?
AFAIK there is no built-in way to do this, so you'll have to do it manually by handling the show and hide events as you mention.
ViewStack does however have two methods "saveState" and "loadState" which could perhaps help you out with this. The history manager uses these methods to enable back/forward navigation. The docs don't seem to have any examples though.
ViewStacks can be the work of the devil when it comes to creation/deletion policies and managing state. We had all sorts of problems when we developed fiat ecoDrive and by about 3/4 of the way though we we're all very anti ViewStacks for the management of view state within our application.
However... a good bet would be to first set the creationPolicy to ContainerCreationPolicy.NONE. That way it's in your control as to when to create any of the panels in your ViewStack. Then i would think you would need to have some sort of logic so that as the ViewStack changes a panel it deletes or resets the one you were on.
Another viable alternative would be to use view states instead. Have a base state which acts as the main container and then a simple state for each of your sections. That way when you switch to a new state, the old state gets removed in reverse order to the way it was created. You do have to be disciplined with states though as they can end up getting really complex and messy when they start becoming nested. If you keep it simple it may work as you require.
In MXML 2009, you can use itemDestructionPolicy="auto" to destroy a component after use it. If you use this property in the first view component with two states (init, logged), you can destroy and reinitialize all child view components. Example :
<s:states>
<s:State name="init" />
<s:State name="logged" />
</s:states>
<s:SkinnableContainer id="skincon" width="100%" height="100%" backgroundAlpha="0"
backgroundColor="#FFFFFF">
<s:VGroup id="MainContainer" width="100%" height="100%" paddingTop="0"
paddingLeft="20" paddingRight="20" gap="0">
<views:_HeaderView id="header" />
<mx:ViewStack id="viewStack" width="100%" height="100%">
<s:NavigatorContent includeIn="init" itemDestructionPolicy="auto">
<s:layout>
<s:VerticalLayout horizontalAlign="center" verticalAlign="middle" />
</s:layout>
<views:LoginView title="Login" id="loginView" />
</s:NavigatorContent>
<s:NavigatorContent includeIn="logged" itemDestructionPolicy="auto">
<s:layout>
<s:VerticalLayout horizontalAlign="center" verticalAlign="top" />
</s:layout>
<views:_CentralView id="userView" />
</s:NavigatorContent>
</mx:ViewStack>
<views:_FooterView id="footer" />
</s:VGroup>
</s:SkinnableContainer>
Both answers are correct -- there doesn't seem to be any built-in way to do it. I solved the problem by creating a "wrapper" component for my view component. It creates a new view component each time the view is shown. This isn't ideal, but fits my requirements nicely, and required few changes to my application structure.
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" show="init()" hide="cleanup()">
<mx:Script>
<![CDATA[
private var myComponent:MyComponent;
private function init():void
{
myComponent = new MyComponent();
componentContainer.addChild(myComponent);
}
private function cleanup():void
{
componentContainer.removeAllChildren();
}
]]>
</mx:Script>
<mx:Canvas width="100%" height="100%" id="componentContainer" />
</mx:Canvas>
Build your "views" as separate Modules, and then use the ViewStack to switch between them. You could then write a function to destroy the unused module(s) (check each module against the selectedChild property) when the ViewStack's "change" event is fired.
2ยข
I am using different states for my different views. On each state change i add and remove components.
This causes the add and remove events of UIComponent fire which allows me to initialize and cleanup my components each time they are added.
This is the idea...
<mx:states>
<mx:State name="state1">
<mx:AddChild>
<mx:SomeUIComponent id="myComp" add="myComp.initialize()" remove="myComp.cleanup()"/>
</mx:AddChild>
</mx:State>
</mx:states>

Resources