How to pass data from one component to another component in flex - apache-flex

I have one class named as EmployeeResult where I am getting the response from the service. Inside the resulthandler I am getting an array of employees like name, id, age etc. I have one dataGrid inside the employeeView.mxml file. Inside the employeeView.mxml file I have an ArrayCollection which is the dataprovider to the datagrid. I want to update that arraycollection from inside the EmployeeResult file. When working with Cairngorm framework I have used the arraycollection inside the singleton to achieve the goal. In case of mate framework I have used the propertyinjector tags. But how do I achieve this objective in my case without any framework. How to achieve property injection without using ane framework or singleton class.

Continuing on your previous question: How to listen to events inside the child component dispatched by the parent component, you can simply dispatch a custom event containing that list of employees and notify the entire application of its arrival.
Something like this:
private function handleMyEmployeeResults(event:ResultEvent):void {
var employees:IList = EmployeeResult(event.result).employeeList;
dispatchEvent(new EmployeeEvent(EmployeeEvent.LIST_LOADED, employees, true));
}
Since this is a service result handler, we may assume that its class instance is not a view and hence it is not on the display list, which is why the event can't bubble. To address this we can dispatch the event directly on the stage.
FlexGlobals.topLevelApplication.stage.dispatchEvent(
new EmployeeEvent(EmployeeEvent.LIST_LOADED, employees)
);
Any view in your application can now listen for this event and set its properties accordingly:
//inside View1
stage.addEventListener(EmployeeEvent.LIST_LOADED, handleEmployeesLoaded);
private function handleEmployeesLoaded(event:EmployeeEvent):void {
myDataGrid.dataProvider = event.employees;
}
//inside View2
stage.addEventListener(EmployeeEvent.LIST_LOADED, handleEmployeesLoaded);
private function handleEmployeesLoaded(event:EmployeeEvent):void {
myOtherKindOfList.dataProvider = event.employees;
myFirstEmployeeLabel.text =
event.employees[0].firstname + event.employees[0].lastname;
}
Another more straightforward approach is to use your Application as a singleton. Create a bindable property employeeList on your main application. Now set its value when the results come in:
private function handleMyEmployeeResults(event:ResultEvent):void {
var employees:IList = EmployeeResult(event.result).employeeList;
FlexGlobals.topLevelApplication.employeeList = employees;
}
Now you can bind to this property from anywhere in your application.
<View1>
<s:DataGrid dataProvider="{FlexGlobals.topLevelApplication.employeeList}" />
</View1>
<View2>
<s:List dataProvider="{FlexGlobals.topLevelApplication.employeeList}" />
</View2>
Though this approach has the merit of being very easy to implement, it has all the downsides of a Singleton (e.g. poorly testable).

Given the types of questions you've been asking, you really should be considering a Framework such as Robotlegs or Mate. They give you the tools to wire your application together without horrible hacks that will limit your flexibility or complicate maintenance long-term.
Check out my previous answer here for links to the same project done without a framework, with Mate, and with Robotlegs.

Related

swt/jface databinding: PojoProperties vs PojoObservable

I'm writing a JFace dialog, and I'd like to use databing to a model object.
Looking at code I can see that there are times when I find a PojoProperties used to build the binding, while other time it is used a PojoObservables.
Looking at the Javadoc I can read:
PojoObservables: A factory for creating observable objects for POJOs (plain old java objects) that conform to idea of an object with getters and setters but does not provide property change events on change.
PojoProperties: A factory for creating properties for POJOs (plain old Java objects) that conform to idea of an object with getters and setters but does not provide property change events on change.
The same question applies to the difference that exists between BeansObservables and BeansProperties
The (obvious) difference sems to be that the observable allows to observe objects and the properties allows to observe properties, but since a Pojo has a getter and a setter for its data, what is the difference between them? And which of them should I choose for my dialog?
Here follows a code excerpt:
The POJO:
public class DataObject {
private String m_value;
public String getValue() {
return m_value;
}
public void setValue(String i_value) {
m_value = i_value;
}
}
The DIALOG (relevant part):
#Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
m_combo = new Combo(container, SWT.BORDER);
m_comboViewer = new ComboViewer(container, SWT.NONE);
}
The BINDING (relevant part):
// using PojoObservable
IObservableValue observeValue = PojoObservables.observeValue(m_dataObject, "value");
IObservableValue observeWidget = SWTObservables.observeSelection(m_combo);
// using PojoProperties
IObservableValue observeValue = PojoProperties.value("value").observe(m_dataObject);
IObservableValue observeWidget = ViewerProperties.singleSelection().observe(m_comboViewer);
I understand that one time I'm using a combo and another I'm using a ComboViewer, but I can get the combo from the viewer and bind the other way if I need...
Also, can I mix the two, for example use the observeValue with the ViewerProperties?
IObservableValue observeValue = PojoObservables.observeValue(m_dataObject, "value");
IObservableValue observeWidget = ViewerProperties.singleSelection().observe(m_comboViewer);
I am playing around a little with JFace viewers (especially ComboViewer) & databinding and discovered that if I use
SWTObservables.observeSelection(comboViewer.getCombo());
then databinding is not working correctly.
However, if I use
ViewersObservables.observeSingleSelection(comboViewer);
Then everything is working as expected.
Maybe this is a special for my case, so to get it a better overview I'll describe my set up in following paragraph.
I have modelObject with field named selectedEntity and entities and bind this ComboViewer to the modelObject.
I want to display all "entities" in model object, if I add any entity to the modelObject.entities collection then I want to this entity be added to combo automatically.
If user selects some item in combo I want to modelObject.selectedEntity be set automatically.
If I set modelObject.selectedEntity I want to combo selection be set automatically.
Source code can be found at: https://gist.github.com/3938502
Since Eclipse Mars, PojoObservables is deprecated in favor of PojoProperties and BeansObservables is deprecated in favor of BeanProperties so the answer to which one should be used has now become evident.

Flex data binding with View-Model pattern

I'm trying to move toward using the View/Model/View-Model or Presentation Model pattern in a Flex application since it definitely feels like the "correct" way to do things. I have a question about how something should work with Flex data binding though.
Say I have a Project model class which contains a bindable name field. I want to make a report to display information about the project. The title of the report should be [Project Name] Summary. I want to make a View-Model class to provide the backing for the report. This SummaryViewModel class will have a title field to provide the report title.
In my report mxml I would bind the title label to summaryModel.title, however title needs to somehow be bound to projectModel.name so if the name is changed in another part of the program the report title updates also.
What's the correct way to accomplish this "two-level" data binding in Flex? Should I be doing things a different way?
Let's say you have a model like this:
[Bindable]
public class Project {
public var name:String;
}
And you have your presentation model:
[Bindable]
public class SummaryPresentationModel
{
private var projectModel:Project = new Project();
public var title:String;
}
In your constructor, you can data bind the setter of the model to a function that sets the title:
public function SummaryPresentationModel() {
BindingUtils.bindSetter(modelNameChanged, projectModel, "name");
}
And then set the value of title:
private function modelNameChanged(newValue:String):void {
title = "[" + projectModel.name + "] Summary";
}
You are then free to bind to the summaryPM.title and everything will chain to the UI when projectModel.name changes.
You can get more complicated and use a "getter" function on title (as opposed to just setting it like I am here), but you need to propagate the change notification. I is not too terribly difficult to do, but I find that this method is a bit easier to follow.
Hope this helps!
No different than any other binding, they will both be updated (both being the place you're putting the title and the summary model).
If you post how you are defining your values I can help you with syntax, but this isn't a difficult binding operation. Where things get mildly more complicated would be with two way binding.

Flex: Which way should I add this event handler?

I use a unit of work pattern a lot in my flex projects. I'll have a class that might call a web service, put the data in a sqlite db, refresh a model with the data then raise an event.
I usually call these inline and pass in some singleton classes:
protected function CareerSynced():void
{
var process:ProcessWorkouts = new ProcessWorkouts(_dataModel, _trainerModel, _databaseCache, _database.Conn);
process.addEventListener("AllWorkoutsProcessed", AllWorkoutsProcessed);
process.UpdateAllUnprocessed();
}
I'll then get the response like this:
private function AllWorkoutsProcessed(event:DataReceivedEvent):void
{
//do something here
}
My question is, am I adding that event listener correctly? I think I might be causing a memory leak, but I'm not sure. I've also thought about using a weak reference. I'm confused about when to use them. Would this be one of those cases?
Should it be like this?
process.addEventListener("AllWorkoutsProcessed", AllWorkoutsProcessed,false, 0, true);
I would either go with the weak reference or just remove the listener:
private function AllWorkoutsProcessed(event:DataReceivedEvent):void
{
event.target.removeEventListener("AllWorksoutsProcessed",AllWorkoutsProcessed);
}
I could list out my reasons but I'll just point you to this.

Robotlegs Flex - How deal with mediators being initialized after creationComplete?

I'm trying to build a Flex application using the Robotlegs framework and don't know how to deal with the creation of mediators (-> onRegister being called) only after the creationComplete event of the view component.
My application loads several XML files at startup, models are created from the files and then dispatch events with the data.
Problem: When "loading" embedded/local files at startup, the model events are dispatched way before the mediators listeneres are added, although they're mapped before triggering the initial data load in the main context.
Is anybody using robotlegs with flex and has foud a "cleaner" way around this, than manually dispatching an event in the mediators onRegister? As doing so the "automatic" mediation would not really be automatic anymore ...
Edit:
Minimal example code:
Context:
override public function startup( ):void{
mediatorMap.mapView( EditorMenu, EditorMenuMediator );
commandMap.mapEvent( ContextEvent.STARTUP, LoadConfigurationCommand );
dispatchEvent( new ContextEvent( ContextEvent.STARTUP ) );
}
LoadConfigurationCommand:
[Inject] public var configurationService:IXMLLoader;
override public function execute():void{
configurationService.loadXML();
}
ConfigurationService:
public function loadXML(){
trace( "xml loaded" );
dispatch( new XMLLoadedEvent( XMLLoadedEvent.CONFIGURATION_LOADED, result ) );
}
EditorMenuMediator:
override public function onRegister( ):void{
trace( "menu onregister" );
addContextListener( XMLLoadedEvent.CONFIGURATION_LOADED, handleXmlLoaded, XMLLoadedEvent);
}
The trace "menu onregister" is happening way before the trace "xml loaded", so the mediator's not listening when the XmlLoadedEvent is dispatched.
I approach this with the StateMachine and grab control of the order of operations. Another approach here would be to add the listener, but also inject the model and check it for data in onRegister. Either approach should put you in front of the race conditions.
I'm not expert in RobotLegs (I'm actually a Parsley addict), however, if you're using a Mediator pattern, that means that your mediator has direct access to the view itself. How about you create an interface class for all your views that has an init public function which your mediator could call after the onRegister.
Maybe Robotlegs has another way of doing it with metadata or events or something, but this is still valid.

Is there any way to add a valueCommit lifecycle to non-mxml components in Actionscript?

The invalidate/commitProperties model used by mxml components is very useful, in my experience, and I'd like to be able to make use of it in domain model objects in my actionscript applications. How can I go about adding lifecycle events like that to my objects? Is there a global object lifecycle manager?
As noted by Robert Bak, you're essentially on your own to implement such a mechanism for non-UI components.
I've found this a very useful technique to use on model classes, since it can dramatically reduce the "thrashing" of bound-property updates when your model classes are not simple data transfer objects - i.e. they have any kind of multi-property logic encapsulated within them.
Since my use-case is for model objects, I didn't need all the methods of IInvalidating.
Here's my particular implementation as a starting point for your own efforts. Note that this comes from a "base model class" we use called RAFModel and that this is for the Flex 4 SDK.
// INVALIDATION AND COMMITPROPERTIES PATTERN
private var invalidatePropertiesFlag:Boolean;
public function invalidateProperties():void
{
if (!invalidatePropertiesFlag)
{
invalidatePropertiesFlag = true;
invalidateModelObject(this);
}
}
protected function commitProperties():void
{
// override this
}
// -- INVALIDATION SUPPORT
public static var invalidObjects:Dictionary = new Dictionary(true);
public static var validatePending:Boolean = false;
public static function invalidateModelObject(obj:RAFModel):void
{
invalidObjects[obj] = true;
if (!validatePending)
{
validatePending = true;
FlexGlobals.topLevelApplication.callLater(validateObjects);
}
}
protected static function validateObjects():void
{
var invalidQueue:Dictionary = invalidObjects;
// start a fresh tracker for further invalidations
// that are a side effect of this pass
invalidObjects = new Dictionary(true);
// ready to receive another call
validatePending = false;
for (var o:* in invalidQueue)
{
var rm:RAFModel = o as RAFModel;
if (rm)
{
// clear the flag first, in case we're reentrant
// on any given instance
rm.invalidatePropertiesFlag = false;
rm.commitProperties();
}
}
}
Invalidation and commitProperties isn't linked to MXML (you can use it with as components) but it is linked to the flex managed visual component lifecycle (as they are the only ones which need to be synchronized with the flash frame by frame rendering). So unless you're talking about visual components it will not work out of the box.
But if you're looking to implement the same mechanism for your non-visual classes, you should probably start by implementing IInvalidating (docs) and creating a mechanism that calls the validateNow() function when the validation needs to be done.
The Flex Component LifeCycle is designed to handle a User Interface Component's creation, destruction, and changes during the time in between. I, personally, do not find the approach appropriate for non-User Interface components.
You could, if you wanted, extend UIComponent in your domain model objects and then add that domain model as a child to a container. it would then go through the Flex Component LifeCycle validation phases (commitProperties, updateDisplayList, and measure).
But, I would not recommend that approach.

Resources