Give us a call 203-379-0773
Check out our Angular Book Series.

How does one Flex Component talk to another Flex Component?

I think there is one question that has come up hundreds of times on Stack Overflow. The question is "How does one Flex Component call a method in another Flex Component?" or some variation thereof. Sometimes people want to access something in the main application, sometimes they want to access something inside an itemRenderer, other times they want to access another child of a ViewStack. No matter the purpose, I feel it is time I create the most detailed answer to the question I can.

The Setup

First let's pretend you have a setup like this:

Click the image to see a larger version.

Something like this would not be uncommon in an application you were building with Flex. At the root of everything in a Flex Application is your main Application file, usually extending s:Application or mx:Application.

Inside the application contains two main components, ComponentA and ComponentB. These could represent two separate pieces of the app and are never showed together at the same time. Or they could represent two different components that are both shown at the same time and make up a single screen.

Inside Component A, is a ViewStack with three children. ComponentB contains a list class, which could be a List or a DataGrid or something else. The List class uses an itemRenderer. Many beginner developers make the mistake of thinking that the itemRenderer represents a single component; however a new instance of the itemRenderer is created for every item displayed in the list. It is an important distinction that many people do not understand.

The implementation of an application like this could be done across many different files or it could be done in a single MXML file. When creating a single MXML file, the parent child relationship can be hidden from the beginner, because it looks like the main application is the parent of every child. It is important to remember the true component hierarchy when thinking about how components should interact with each other.

Events Communicate Up

Many questions relate to executing a method in their parent from a child. For example, what if you want to change the selectedIndex of the ViewStack from within Child1? Perhaps you're building a multi-step process and the user just clicked a 'next' button. Or perhaps the user was viewing data in a DataGrid and clicked an 'edit' or 'more details' button that is supposed to open up a new screen with additional information. All these are valid use cases. So, how do you do it?

From an encapsulation stand point, a component should never try to execute methods in its parent. Doing so gives the component a dependency upon the parent; thus minimizing reuse. The child component cannot then be used as the child of a component other than the parent

The solution for a component to tell its parent to do something is to use events. An event is dispatched from the component to its parent. The parent will listen to events from its child and execute handler methods to perform some functionality. Flex makes use of this model all over the place such as the click on a button or the input of keystrokes into a TextInput.

The code isn't that difficult. First create an event class:

var myEvent = new Event('myEventType');

And then dispatch the event:

dispatchEvent(myEvent);

If you need to send custom data with your event; you can create your own event class to do so; but I decided to keep such details out of this article. For bonus points you can use metadata to define your event as part of the class. This is primarily used for code hinting within an IDE and does not affect things at runtime. This is sample event metadata:

[Event(name="myEventType", type="flash.events.Event")]

You can put that metdata before the class definition if you have an ActionScript class; or as part of the fx:Metadata tag in an MXML class.

Dispatching the event is only the first step, though. The parent is going to have to add an event listener to it. In MXML this is easy, as the event will show up as if it were a property on the component, like this:

<ns1:Child1 myEventType="myEventHandler(event)" />

If you want the above method to work, you'll need to add in the event metadata. However, if for some reason you don't want to create event metadata, you can also add listeners in ActionScript. You use the addEventLIstener method on the instance of your component. The instance is named by using the id tag in MXML or the variable name in ActionScript:

myChild1.addEventListener('myEventType',myEventHandler);

Either method for adding an event listener will call a method, known as the event handler:

protected function myEventHandler(myEventHandler:Event):void{
// do stuff here
}

Events are the proper way that a component can communicate with its parent. If the component is on the display list; the events can also bubble. Using our example, if myChild1 dispatches the myEventType; first the ViewStack event handlers will execute. If ComponentA added a listener on the ViewStack for the myEventType event; that will execute next. If the main application had an event listener on ComponentA for the myEventType, that event handler will execute next.

Event bubbling is the proper way for a renderer to communicate with the parent of its List. Dispatch an event from the renderer, make sure it bubbles by setting the bubble property of the event's constructor to true, and then listen for the event on the List.

Inside the renderer, you create the event, with the bubble flag to true and dispatch it normally:

var myEvent = new Event('myEventType', true);
dispatchEvent(myEvent);

In ComponentB you can add an event listener to your List class:

List.addEventListener('myEventType', myEventHandler);

You won't be able to add the event listener in MXML unless you extend the list class to include custom metadata as we showed above. But, even without metadata the event will still bubble and the event listeners will still execute.

Methods Communicate Down

Events are how a component should communicate up to its parents. But, how does a parent communicate down to its children? There are two different ways, either by executing a public method on the child or by changing properties on the child. Public methods and properties make up the API which a component expects its parents to use to control its behavior.

Creating a public method is no different than creating an event listener, like we did above. It just uses a different access modifier, specifying public instead of protected:

public function myMethod(argument:ArgumentType):void{
// do stuff here
}

You can specify as many arguments as are needed to perform the method functionality. A good example of this is the addEventListener method. That is a method built into Flash's architecture, but you can write your own methods using the approach above to perform your own functionality. The Flextras Calendar component, for example, has a method to change the view between month, week, and year.

A component would call this method on the instance of the component, specified by the MXML ID. So, if the ViewStack component wanted to call myMethod on the Child2 it would do this:

myChild2Instance.myMethod(myArgument);

Methods can return things by specifying the return type in the method signature. Our example above specifies the return type as void, which means the method doesn't return anything. Here is another method which returns a Boolean value:

public function myMethod(argument:ArgumentType):Boolean{
// do stuff here
// return result
return true;
}

The code you put inside the method, the arguments you choose, and the return value will all depend upon the functionality you want to achieve in the method.

Properties Communicate Down

Changing properties values are the second way that a parent can communicate with its child. As one example, a component's position in the display list is defined with the properties X and Y. The labelField on a list, or the selectedIndex property on a ViewStack are other examples of properties. Properties are implemented as public variables within a component.

They can be implemented with a simple variable definition:

public var myProperty :MyType;

This is the easiest way to create a property on a component. You can also create properties using a special set of methods, named get and set methods. If you want to perform other functionality when setting, or retrieving the value of your variable, then getter and setters are what you need. This is a common implementation:

private var _myProperty :MyType
public function getmyProperty():MyType){
return _myProperty;
}

public function set myProperty(value:MyType):void{
_myProperty = value;
}

The simple public variable becomes private; and the API for setting or retrieving these methods lie within the get and set methods which access the private value. It is very common in the Flex Framework for a set method to be used to dispatch a change event for the component. If you want a property to be read only, you can leave out the set method.

Whether implemented as simple variables, or with get/set methods, properties are accessed identically from the component trying to change the property. For example if ComponentB wants to set the selectedIndex on the List it would do this:

list.selectedIndex = 1;

It doesn't matter how the list has implemented the property for selectedIndex. This is a form of encapsulation I call implementation hiding. One component does not need to know how another is implemented. It should only communicate with it through its public API. The API is defined through documented properties, methods, and events.

Other Thoughts

Components that are on the same level of each other, such as Child1 and Child 2 should not communicate directly with each other. The proper way to have Child1 affect Child2 is to dispatch an event from Child1; have your ViewStack component listen to the event and call a method, or property, on Child 2.

There are other methods for sharing data between components, such as using Dependency Injection to share class instances between components. Another may be to use a Singleton class. Many frameworks exist to help with these things, but it is beyond the scope of this article. Your key takeaway from this article is that the use of events, properties, and methods can help you create robust, reusable components within your application.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Tink's Gravatar I would advise users in most cases to avoid inter-component communication, unless they are building a complete component. Instead communicate with a form of a controller, update a model, and have your view reflect the model.

Inter-communication will only end up with a web of messy communication throughout yur application.
# Posted By Tink | 2/1/13 11:09 AM
Jeffry Houser's Gravatar Tink,

I don't understand what you mean by "inter-component communication" nor "complete component".
# Posted By Jeffry Houser | 2/1/13 11:57 AM
Antonos's Gravatar IMHO
bubbles=true is wrong way for itemRenderer
better to dispatch direct
owner.dispatchEvent(new Event('myEventType'));
since bubbles means it will bubble to top
(for sure you can stop propagation in handler, but direct approach is better
# Posted By Antonos | 7/15/13 10:51 AM
Jeffry Houser's Gravatar @Antonos

I couldn't disagree more.

Accessing the owner, or parent, is a break in encapsulation. It'll work; and if you don't care about encapsulation in any way then it doesn't matter.

But, most people do care about encapsulation, and potential reuse, of their code. Accessing the owner or parent can interfere with that ability.

It is better to stop bad habits before they start.
# Posted By Jeffry Houser | 7/15/13 11:44 AM
Dhanraj's Gravatar thnx.....
# Posted By Dhanraj | 9/26/13 6:42 AM
hawa4frnds's Gravatar I am having a mx advanced data grid with custom itemRenderer and custom groupItemRenderer.
I want to call some methods of both renderers from the parent components of datagrid..

I don't want to change the data, I just want to change some UI appearance inside renderers when something happens outside.

How can I achieve this?
# Posted By hawa4frnds | 9/10/15 11:51 PM
Jeffry Houser's Gravatar @hawa4frnds

If you want to change styles for all itemRenderers, you may be able to do that by changing the relevant styles on the DataGrid; which should pass onto the renderer.

However, if you want to change some renderers, but not all of them it is going to be extremely difficult to do so without having your design changes based on the data somehow. Remember that renderers are re-used as the user scrolls through the DataGrid. So, you'd have to write your own code, outside of the DataGrid, to determine what is being displayed and how it should change and it sounds like a nightmare.

--JH
# Posted By Jeffry Houser | 9/11/15 8:15 AM