Access component id of one mxml from another - apache-flex

I have two mxml files. one is main that is application tag mxml file and another is my mxml component file.
I have a viewstack in my main mxml whose id is, say, "mainViewStack".
Now I want to set selectedChild property of "mainViewStack" from my mxml component file.
But I m getting error:
Error #1009: Cannot access a property or method of a null object reference.
on accessing mainObj.mainViewStack.selectedChild.id where mainObj is the object of main mxml file.
Please help me out.
Thank u.

My guess is that you're trying to access the child before it's created. But that's hard to tell without the code.
Try waiting until the FlexEvent.CREATION_COMPLETE event on the application to access the selected child.

This issue is referred to as "deferred instantiation" and is a product of the Flex Component Lifecycle. If you want an extremely thorough explanation of this concept, this white paper is probably the best I have read.
Essentially Flex creates components as they are needed. Each component has a lifecycle that takes it through stages:
Construction
Addition
Initialization
Invalidation
Validation
Update
Removal
A sub-component isn't going to be accessible until it has passed through the initialization phase. This is the point at which a Flex component will dispatch its CREATION_COMPLETE event, letting you (and the framework) know that it is ready for interaction. Prior to this event, you are going to receive null reference errors when attempting to access the component or its children.
ViewStacks compound this by default by not initializing sub-components until they are called for display. The creationPolicy property of a ViewStack, by default, is set to auto. There are several options for this property, including all. Be aware, however, that this can potentially present severe performance issues, as all of the components inside the stack are going to be initialized immediately regardless of whether or not the user actually even looks at the component.
In your specific case this isn't the problem. The component that contains the view stack hasn't been completely initialized. You need to set the child of the ViewStack in a CREATION_COMPLETE event handler.

or you can give "creationPolicy=all" because Flex only creates the first visible child from the viewstack

You can use this code in your MXML component to change application's ViewStack selected child from other MXML component. However it is not a good practice.
FlexGlobals.topLevelApplication.mainViewStack.selectedChild = FlexGlobals.topLevelApplication.childId
You can use static event dispatcher to dispatch an event from one view and listen that event in an other view.

Related

Is there a canonical way to get data from a parent in the containment tree?

I have an actionscript-instantiated component in a containment hierarchy; it extends ComboBox, but it's instantiated dynamically--you never know when you're going to need it.
Somewhere up in its containment hierarchy, there's a thing which extends NavigatorContent which logically is the right place to put the valid values for said combo box.
What's the canonical way for that child component to get a reference to that set of valid values?
I would solve this by having the child dispatch a bubbling event (CHILD_CREATED) with a self refrence when it's created. Then simply listen for the CHILD_CREATED event in the object that has access to the set of valid values.
#1 Parent is created - add a listener to know when a child is created and needs a refrence to values
#2 Child is created - dispatches CHILD_CREATED dynamic event with a self refrence as a property
#3 Parent hears CHILD_CREATED - extracts the reference to the child component and sets its data provider to the set of valid values.
EDIT:
A much cleaner way to handle this kind of problem if you are dealing with a component based on DataGroup is to use the rendererAdd (there is a refrence to the renderer in the event). This would definitly be the canonical way to handle it.
So if you are using a DataGroup to display components that you need to access directly, just use the rendererAdd event. If that issn't applicable to your problem, I'd go with the CHILD_CREATED method.
I don't think there is one canonical way to solve this. There are so many possible solutions. You could:
Pass the values as an argument to the child constructor
Pass a reference to the NavigatorContent and then get the values directly upon instantiation
Pass a reference to the NavigatorContent and then add a change listener to it, which fires every time a new value is set
Use a Factory or Factory Method which has a reference to the NavigatorContent to create and populate the child
Create a Proxy or Delegate class to manage creation and data population of all children of the NavigatorContent
...
I'm sure there are tons more.
It all depends on what your program is doing, how the rest of the hierarchy works together, when and if those values are updated, and whatever other requirements need to be fulfilled.
Start from there, then look at the suggestions people have made here, and pick one which suits your scenario best.

Accessing states of parent application in Flex 4

I have several custom components all of which are included in the parent application.
When I try to change state from a custom component, I get an error saying "undefined state: state name". How do I change the state of the application from within a custom component ?
To keep your custom component from being tied to your application I would recommend having the component dispatch a custom event that the parent application listens for. The parent application would then change its own state after receiving the event from the component. Hope that helps.
The simple but wrong way:
(parent as __application-class__).state = "__state-name__"
replacing the terms with underlines with their appropriate names. but as wade pointed out, it's a clumsy, brittle way to do it. If your application is small and not going to be seen by other developers though this is fine.
The right way of doing this would be setting up your main application to change its own state in response to some condition or input such as an event fired by another component.

Flex: Render an unrealized UIComponent to BitmapData?

What is the best way to render to a UIComponent which hasn't been added to the stage? (I'm using UIComponents as renderers for objects, and want to render new copies for image export, filtering, etc.)
Two strategies I've seen/used so far include realizing the component to ensure it calls all the lifecycle methods:
Add the component to Application.application, render with BitmapData.draw(), remove component. This is similar to what I've seen done for printing unrealized components as well.
Add the component to a pop up window, render with BitmapData.draw(), dismiss popup after rendering complete.
I believe both of these just rely on the UI not refreshing while the current thread/event is executing, though (1) could also rely on the component being realized out of view.
Is there a better way?
What I've used in the past with much success is the following:
Create a new instance of your component
Add an event listener for FlexEvent.CREATION_COMPLETE
Set visible=false on the component
Add the component as a child of the main Application
When the component is created, the event listener function will be invoked. The rest of the logic should be put in / invoked from your event listener function
Remove the event listener you added in step #2.
Use ImageSnapshot.captureImage() or captureBitmapData() to capture the visual representation of the component.
Remove the component from the main Application
Process the image data as you need to.
I've used this to snapshot various Flex charting components for use in PDF's generated on the server side. After getting the BitmapData I use the PNGEncoder or JPEGEncoder classes to compress the data, then encode it in Base64 before uploading to the server.
I'm pretty sure you can use the draw() method in BitmapData without having your component on the DisplayList.
For example is use it when I need to modify images I load with the Loader Class. In the init handler I create a BitmapData instance and draw the Bitmap from the loadInfo.content property, then copyPixels() or whatever I need to modify the loaded image
So much of a UIComponent's layout can be tied to it's context. This is especially true for a lot of its derivatives (e.g. HBox) since the fluidity of the layout is tied to it's parent's size and the number of siblings sharing its parents space.
Additionally Flex can be a real pain to get to visually update. Often critical render functions aren't done synchronously ... there are callLater, callLater2 and other hacky approaches that make dealing with the auto-magical layout properties of UIComponents a major headache. Not even calling validateNow or updateDisplayList can guarantee that the layout will be correct on the current frame (instead of a few frames in the future).
I suggest the best thing you can do is not use a UIComponent and try and use a Sprite or other.
Your approach to attach it but make it invisible (alpha = 0, mouseEnabled = false, mouseChildren = false) is decent. You should listen for the FlexEvent.CREATION_COMPLETE callback before you are certain it is properly laid out. Then you can bitmapData.draw it and then remove it from the stage. If you must use UIComponents then I know of no better way.
You can call the lifecycle function manually before using the BitmapData.draw(). Do the following.
createChildren().
commitProperties().
updateDisplayList().
bmd.draw().
The first 2 steps are not 100% necessary, you can put all codes into updateDisplayList(). Because you invoke the function manually, you don't have to worry this is invoked by Flex framework many times.

Flex Viewstack's children, if you can't see them, do they exist?

I seem to be running into an issue (Cannot access a property or method of a null object reference) binding events in actionscript to a viewstack layer not currently showing. Are those objects not created until that layer is visible for the first time? I remember something about a creation policy, if this is the case, can I force it to create those children before that layer is viewed?
Yes, that's right -- ViewStack children are created only when needed by default ("deferred instantiation" is a phrase you'll hear thrown around in this context). If instead you want to instruct Flex to create all of the ViewStack container's children up front, consider using the creationPolicy property common to all mx.core.Containers:
A creationPolicy of
ContainerCreationPolicy.ALL means that
the navigator containers immediately
create deeper descendants for each
child, rather than waiting until that
child is selected.
<mx:ViewStack id="myStack" creationPolicy="all" />
It's a bit slower on startup, because you're creating a bunch of child components you might not need yet, but as long as you keep that tradeoff in mind, it may come in handy sometime.
Yeah, I had this same problem myself while working on an application with a PureMVC structure. I was unable to create mediators for the subcomponents of a ViewStack because they were constructed lazily by the Flex framework.
Here's where I eventually found my solution:
http://forums.puremvc.org/index.php?topic=280.0
Found the relevant documentation here. Seems like that'd be something you'd make a note of on the container docs.

How to tell when an MXML component has totally finished creation?

An MXML component can be quite complex, containing many nested controls, including asynchronously loaded content such as Image/SWFLoader.
Is there one event I can watch for on my component that will only be raised when every control and sub-component has loaded, including SWFs and Images?
CreationComplete will NOT do the trick if you are talking about loading swf content or anything really external like that. CreationComplete gets fired when the MXML components have been laid out as defined in MXML (IE nested components, buttons, boxes, canvasses, etc.), so content that needs to get loaded externally (an image, a swf) does not count.
What you need to do is keep track of everything that you're waiting for and fire off a custom event once all of those elements have loaded.
One possible hackish way to do it would be to listen for whatever load complete event is relevant for each element, then have them call back to the same function that increments a value equal to the number of components you're waiting for. This means you have to pay more attention if you're modifying it, but it also means you don't have to check a boolean for every element that needs to load (IE "if (image1Loaded && image2Loaded && swfLoaded)" etc.)
The onApplicationComplete event?
The creationComplete event should do the trick - creationComplete is called on the parent component after it is called on the children.
You can get some more info on the component lifecycle in the Adobe docs.
In some complex cases, like when your component is considered "finished" only when some data has been retrieved via HTTP or something like that, custom event is your best bet.

Resources