How can i access a variable or change the state of an element(like tabNavigator) from one mxml to another mxml? - apache-flex

How can i access a variable or change the state of an element(like tabNavigator) from one mxml to another mxml in FLEX 4.6??

Each separate MXML file should be viewed as a class, since that is what they are.
In the theory of encapsulation; two classes should not directly access / change each others variables or state. They should use an API provided by the developer of the MXML Class.
If MXML 1 is the parent of MXML 2; then MXML1 can pass data to MXML2 by setting public properties or calling public methods.
MXML2 can pass data to MXML1 by dispatching events.
If MXML1 and MXML2 are not in a parent child relationship; (AKA Both children of the same component as one example) they they should not communicate with each other directly. They should dispatch events which the mutual parent should handle and use to set values or execute methods on it's own children.
From an encapsulation standpoint, that is how it should be done using the built in facilities of ActionScript / Flex.
What a lot of people do as part of building applications is to make use of dependency injection. That was values that are "global to the application" can be shared among multiple components. Another approach to doing this is to use a Singleton. A third approach might be to make use of static values on a class; which can be accessed without accessing an instance of a class.

Related

Making class vars available to external itemRenderer classes

I made a custom itemRenderer, and need to access a variable in my Project file (mxml). How can I make my public var available in the custom itemRenderer file?
public function lang_f(trans_short:String):String{
if(outerDocument.language == "de"){
...
}
}
Greetings
Markus
You shouldn't access outer document data from within item renderer. It breaks OOP principles such as low coupling etc. You should either set this data to item renderer with data from data provider or extend your list based component to instantiate renderers with that data. And don't think about MXML component as files. The file structure is just a form of representation. You'd better think MXML files as classes or components — in terms of application structure.
To go along with Constantiner's answer, if you still need to access that variable, you can access the variable in your itemRenderer using outerDocument:
outerDocument.myVariableName
Is the variable defined in main file of your application ? If that's the case you can access is using FlexGlobals.topLevelApplication.YOUR_VARIABLE_NAME
However I agree with Constantiner. This violation of OOP principles. But I hope that solves your problem.

flex sharing data between different components

i have in my flex application various mxml components that all need to show stats based on the same data. how can i go about doing that? do i need some mvc framework like cairngrom or puremvc for that or can i do it without them?
any design ideas?
You don't need any framework for that. Do you know about data-binding?
http://www.flexafterdark.com/docs/Flex-Binding
This way you can set your data as dataprovider for many components. For example to show your data in dataGrid you set in mxml it's attribute
dataProvider="{yourDataArrayCollectionIdentifier}"
and in your arrayCollection declaration you need to set metatag [Bindable]
[Bindable] var yourDataArrayCollectionIdentifier : ArrayCollection;
there are other datatypes you can use as dataprovider, just arrayCollection is the most common
There are a handful of approaches to this. For encapsulation purposes, you should isolate your shared data out into a separate class; possibly a Value Object although it does't have to be.
Then create a public variable property in each MXML Component of this classes type. When you create the instance of each mxml component, pass in your 'global' instance of the data class.
You don't need to use an MVC framework, but the Cairngorm Model Locator could also be used to address this problem. The Model Locator is a singleton. You'd store your data inside the singleton instance; and then each MXML Component would reference the singleton for the data. Creating an external dependency like this breaks encapsulation, though. I much prefer the parameter passing route for non-application specific components.
package
{
public class ApplicationViewModel
{
[Bindable] public var message:String = "";
}
}
You can now use this message across your MXML where you make the instance of that.
A singleton class is used in different scenarios where you want to hold some information of all states. A better example would be Chess Board, where your board is Singleton class and its state should never change as you have to keep track of all coins moved across the board and its position.
You are injecting this message variable in the views where you want to show the data.

Swiz mandates weak encapsulation

I just started using Swiz, and, it seems like Swiz forces you to create classes with weak encapsulation. Swiz requires all event handlers to be public in order to mediate events.
Assume that component 'A' dispatches a few events, which I want to listen to in component 'B'. Traditionally, I'll just add event listeners on 'A' in 'B' and all the event handlers in 'B' can be kept private. However, if, I am using Swiz, I need to make all the handlers, mediating events, public.
Am I missing something here, is there a way to bypass this problem. I really, don't want to pollute the public interface of my class.
Thanks.
As I mentioned on the mailing list, there is no way around it, unfortunately. Since there is no way to access private members of classes, the only way B can use private event handlers for events
from A is if addEventListener() is called from within B. Since Swiz is obviously not operating within your classes, it has no way to access those members.
Swiz aims to keep your application code as free from references (including inheritance) to Swiz classes as possible. Therefore, you can think of it as configuring your app "from the outside". Unlike the JVM, Flash Player simply allows no access to private members, so for Swiz to interact with your code, it has to be public.
You can also create a custom namespace that makes them not necessarily public, but not private either. I use what Openflux originally did:
[Mediate(event="UserEvent.LOGIN")]
metadata function loginHandler(user:User):void
{
... with namespace
}
[Mediate(event="UserEvent.LOGOUT")]
public function logoutHandler(user:User):void
{
... without namespace
}
You then have to add use namespace metadata into the Swiz Processors, and probably to their metadata MediateQueue. As long as the namespace is imported in the correct classes, something that's dynamically referring to a method will work:
so in the setUpMetadataTag method in MediateProcessor (or at the top of the class):
use namespace metadata;
// bean.source[mediateTag.host.name]
// service["loginHandler"] and service["logoutHandler"] both work
addMediatorByEventType( mediateTag, bean.source[ mediateTag.host.name ], eventType );
Makes the code clean, and keeps things from being public. But some people think it's too much work :).
Best,
Lance
For something outside of and decoupled from the class to invoke the handler, the method can't be private. So you have two choices: make them public and let Swiz mediate them (and reap all the loose coupling), or keep them private and don't use the event mediation. If you think it's worth it (and most do), use it. If you don't, don't.
"Swiz requires all event handlers to be public in order to mediate events."
That's true, but Swiz's strength is that it doesn't force any (more or less) design choices on you, it just provides powerful tools (dependency injection, event mediation, et al) that you can choose to apply where you think appropriate.
Using Swiz does not require the use of the [Mediate] tag at all - you can still use addEventListener() and listen from private methods as you normally would (as I'm sure you're well aware). As far as I can tell, the Swiz event mediation is intended primarily for use with system/application level events. If you're calling event listeners within a single component, or within close family components, you would usually use the standard event listeners. To communicate between individual, otherwise-unrelated components, you can handle the message with Swiz's mediator.
In short, in any case where you have access to private event listeners (i.e. within close components), you probably wouldn't be using [Mediate] to capture the event, and so that listener could remain private. When you're using the [Mediate] tag, the event handler is generally in a completely separate location in the application (e.g. presenter -> controller) where it couldn't practically be private in any case.
I may be slightly off, but this is how it appears to me. Swiz may encourage weak encapsulation in some situations, but to me it offers greater modularisation overall.

Two different HTTPService classes in Flex

Why are there two different HTTPService classes in Flex?
this
and
this
And the second one inherits the first one.
Why couldn't there be a single class combining the two?
One of the objects (the first link you posted) is the HTTPService Object itself.
The second is the object that wraps the HTTPService object and gives it the additional functionality for the <mxml /> tag.
The two probably weren't combined because you don't necessarily need the implementation of the IMXMLObject and IMXMLSupport interfaces every time you need an HTTService object.
mx.rpc.http.mxml.HTTPService can also handle concurrency while the other can't.
Edit:
Although in the online documentation I see concurrency as a property of both, several sources say thats not true(and my tests didn't work when I first tried using it). Also the concurrency package is only imported into the mxml.HTTPService, not the base rpc class.
Bug Comment
Mederator comment on the docs page
There appear to be more error handling features in the URLLoader class. Using MXML to create your HTTPService is not a big difference though.
// ActionScript Style
private function myService():void {
var service:HTTPService = new HTTPService();
...service.parameters = value;...
service.send();
}
or
< !-- MXML Style -- >
< mx:HTTPService >
...< parameters >...
< /mx:HTTPService >
The first is a member of the mx.rpc.http package and is used in ActionScript code. The other version of the HTTPService class is a sublass of the first and is a member of the mx.rpc.http.mxml package. This is the version you use when you instantiate the object with the tag.
The versions are nearly identical with two significant differences: only the MXML Version implements the showBusyCursor property, which casuses an animated curser top be displayed for the duration of an HTTPService request/response cycle, and the concurrency property, which determines how multiple concurrent requests to the same network resource are handled.
The concurrency property isn't implemented in the version of the HTTPService class typically used in ActionScript because, when using ActionScript you commonly create a new HTTPService object for each new request.
Source: Adobe Flex 3 Bible - David Gassner

React to change on a static property

I'm re-writing an MXML item renderer in pure AS. A problem I can't seem to get past is how to have each item renderer react to a change on a static property on the item renderer class. In the MXML version, I have the following binding set up on the item renderer:
instanceProperty={callInstanceFunction(ItemRenderer.staticProperty)}
What would be the equivalent way of setting this up in AS (using BindingUtils, I assume)?
UPDATE:
So I thought the following wasn't working, but it appears as if Flex is suppressing errors thrown in the instanceFunction, making it appear as if the binding itself is bad.
BindingUtils.bindSetter(instanceFunction, ItemRenderer, "staticProperty");
However, when instanceFunction is called, already initialized variables on the given instance are all null, which was the cause of the errors referenced above. Any ideas why this is?
You have 2 options that I am aware of:
Option 1
You can dig into the code that the flex compiler builds based on your MXML to see how it handles binding to static properties. There is a compiler directive called -keep-generated-actionscript that will cause generated files to stick around. Sleuthing through these can give you an idea what happens. This option will involve instantiating Binding objects and StaticPropertyWatcher objects.
Option 2
There is staticEventDispatcher object that gets added at build time to classes containing static variables see this post http://thecomcor.blogspot.com/2008/07/adobe-flex-undocumented-buildin.html. According to the post, this object only gets added based on the presence of static variables and not getter functions.
Example of Option 2
Say we have a class named MyClassContainingStaticVariable with a static variable named MyStaticVariable and another variable someobject.somearrayproperty that we want to get updated whenever MyStaticVariable changes.
Class(MyClassContainingStaticVariable).staticEventDispatcher.addEventListener(
PropertyChangeEvent.PROPERTY_CHANGE,
function(event:PropertyChangeEvent):void
{
if(event.property == "MyStaticVariable")
{
someobject.somearrayproperty = event.newValue as Array;
}
});
I think you need to respond to the "PropertyChanged" event.
If you're going to do that, use a singleton instead of static. I don't think it will work on a static. (If you have to do it that way at all, there are probably a couple ways you could reapproach this that would be better).
var instance:ItemRenderer = ItemRenderer.getInstance();
BindingUtils.bindProperty(this, "myProperty", instance, "theirProperty");
After fiddling with this for a while, I have concluded that this currently isn't possible in ActionScript, not even with bindSetter. It seems there are some MXML-only features of data bindings judging by the following excerpt from the Adobe docs (though isn't it all compiled to AS code anyways)?
You cannot include functions or array
elements in property chains in a data
binding expression defined by the
bindProperty() or bindSetter() method.
For more information on property
chains, see Working with bindable
property chains.
Source: http://livedocs.adobe.com/flex/3/html/help.html?content=databinding_7.html
You can create a HostProxy class to stand in for the funciton call. Sort of like a HostFunctionProxy class which extends from proxy, and has a getProperty("functionInvokeStringWithParameters") which will invoke the function remotely from the host, and dispatch a "change" event to trigger the binding in typical [Bindable("change")] Proxy class.
You than let the HostProxy class act as the host, and use the property to remotely trigger the function call. Of course, it'd be cooler to have some TypeHelperUtil to allow converting raw string values to serialized type values at runtime for method parameters (splitted by commas usually).
Example:
eg.
var standInHost:Object = new HostFunctionProxy(someModelClassWithMethod, "theMethodToCall(20,11)");
// With BindingUtils.....
// bind host: standInHost
// bind property: "theMethodToCall(20,11)"
Of course, you nee to create such a utlity to help support such functionality beyond the basic Flex prescription. It seems many of such (more advanced) Flex bindings are usually done at compile time, but now you have to create code to do this at runtime in a completely cross-platform Actionscript manner without relying on the Flex framework.

Resources