Setter is not invoked when a bindable Flex property doesn’t change

Flex Published on May 15, 2010 by Andrea Bresolin 1 Comment »
Live demoSource code (LICENSE)

You’ve probably been using the Bindable metadata tag a lot of times with properties in your Flex applications. When a property is defined through getter and setter functions, you may take for granted that each time you set the value of the property, the corresponding setter is invoked, so you can perform your own operations in it. Well, this is not totally true with bindable properties. What I’m going to show is just something to remember whenever you use the Bindable metadata tag with properties defined through getter and setter. It is much easier to explain everything if we immediately look at the example application.

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	pageTitle="Setter is not invoked when a bindable Flex property doesn\'t change - devahead BLOG"
	layout="vertical" horizontalAlign="left"
	viewSourceURL="srcview/index.html">

	<mx:Script>
		<![CDATA[
			private var _notBindableProp: String = "";

			public function get notBindableProp(): String
			{
				return _notBindableProp;
			}

			public function set notBindableProp(value: String): void
			{
				_notBindableProp = value;

				logValueChange("notBindableProp", _notBindableProp);
			}

			private var _bindableProp: String = "";

			[Bindable]
			public function get bindableProp(): String
			{
				return _bindableProp;
			}

			public function set bindableProp(value: String): void
			{
				_bindableProp = value;

				logValueChange("bindableProp", _bindableProp);
			}

			private var _bindableEventProp: String = "";

			[Bindable("bindableEventPropChanged")]
			public function get bindableEventProp(): String
			{
				return _bindableEventProp;
			}

			public function set bindableEventProp(value: String): void
			{
				_bindableEventProp = value;

				logValueChange("bindableEventProp", _bindableEventProp);

				dispatchEvent(new Event("bindableEventPropChanged"));
			}

			protected function logValueChange(propertyName: String, newValue: String): void
			{
				logArea.text += propertyName + " setter invoked: " + newValue + "\n";
			}
		]]>
	</mx:Script>

	<mx:Form>
		<mx:FormItem direction="horizontal"
			label="New value for the NOT BINDABLE property:">
			<mx:TextInput id="notBindablePropText" width="150"/>
			<mx:Button label="Set" click="{notBindableProp = notBindablePropText.text}"/>
		</mx:FormItem>

		<mx:FormItem direction="horizontal"
			label="New value for the BINDABLE property:">
			<mx:TextInput id="bindablePropText" width="150"/>
			<mx:Button label="Set" click="{bindableProp = bindablePropText.text}"/>
			<mx:Label text="{bindableProp}" fontWeight="bold"/>
		</mx:FormItem>

		<mx:FormItem direction="horizontal"
			label="New value for the BINDABLE property WITH CUSTOM EVENT:">
			<mx:TextInput id="bindableEventPropText" width="150"/>
			<mx:Button label="Set" click="{bindableEventProp = bindableEventPropText.text}"/>
			<mx:Label text="{bindableEventProp}" fontWeight="bold"/>
		</mx:FormItem>
	</mx:Form>

	<mx:Label text="Log:"/>

	<mx:TextArea id="logArea" width="400" height="300"/>

</mx:Application>

The property called notBindableProp is just a simple not bindable property. Whenever you set its value, the setter is invoked. bindableProp is a standard bindable property. If you try to set its value, you’ll quickly find out that the setter is invoked only if the new value is different from the value returned by the corresponding getter. So you cannot rely on doing something inside the setter when the new value is exactly the same as the previous one. What if you still want a bindable property, but you need to perform some operations in the setter every time a value is set, even if it’s equal to the previous one? You can simply define a custom event name in the Bindable metadata tag as you can see in the bindableEventProp. Every time a value is set for that property, the setter is invoked and you can perform your operations and then dispatch your own event.

Disabling user interaction in a Flex application

Flex Published on April 24, 2010 by Andrea Bresolin No Comments »
Live demoSource code (LICENSE)

While working with asynchronous operations like server calls or asynchronous events, you know that it’s not easy to guarantee a correct processing of user’s requests if there isn’t a well defined workflow that the user must follow. For example: the user clicks a button that makes a function call on the server side, so the application waits for the server to reply, but meanwhile the application is still responsive for the user so any other operation could be performed by the user on the interface possibly not compatible with the reply of the server in the moment that the client receives it. There are times when the user interaction must be disabled until the application is again in a state that can safely process any other user request because there’s a well defined workflow to follow. This is the topic of this post, giving you a way to temporarily disable user interaction while the application is not in a ready state.

At this point one could think: well, that’s easy, you can do that simply by setting the enabled property of the components. No, it’s not that easy. The reason why it’s not easy, is because you don’t want the user to see weird color changes in the user interface because a component switches from enabled to disabled state and vice versa and you want to keep the focus on the component that was focused before disabling the interface. So these are the key points that I had to keep in mind while thinking about the solution that I’m going to show you.

As usual, the best way to start is looking at the source code, so we can discuss later about what it does.

package com.devahead.utils
{
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.EventDispatcher;

	import mx.collections.ArrayCollection;
	import mx.containers.Canvas;
	import mx.core.Application;
	import mx.core.IChildList;
	import mx.core.UIComponent;

	public class UserInteractionManager extends EventDispatcher
	{
		protected var _blocker: Canvas = null;

		protected var _managedApp: Application = null;

		/**
		 * Application managed by this UserInteractionManager instance.
		 */
		public function get managedApp(): Application
		{
			return _managedApp;
		}

		protected var _focusState: Object = null;

		/**
		 * Data about the focused components before disabling the
		 * user interaction.
		 */
		protected function get focusState(): Object
		{
			return _focusState;
		}

		protected function set focusState(value: Object): void
		{
			_focusState = value;

			dispatchEvent(new Event("isInteractionEnabledChanged"));
		}

		/**
		 * Tells if the user interaction is currently enabled.
		 */
		[Bindable("isInteractionEnabledChanged")]
		public function get isInteractionEnabled(): Boolean
		{
			return (_focusState == null);
		}

		/**
		 * Constructor.
		 *
		 * @param managedApp
		 *   Application instance managed by UserInteractionManager.
		 */
		public function UserInteractionManager(managedApp: Application)
		{
			_managedApp = managedApp;

			// Create the blocker component to avoid mouse clicks.
			// We set a backgroundColor to actually allow the clicks to be blocked
			// (it doesn't work if the blocker is totally transparent) and we set
			// the backgroundAlpha to a very small number so the blocker is not
			// transparent for the Flash player but it is actually invisible for the
			// human eye.
			_blocker = new Canvas();
			_blocker.setStyle("backgroundColor", 0xffffff);
			_blocker.setStyle("backgroundAlpha", 0.01);
		}

		/**
		 * Disable the user interaction with the application.
		 */
		public function disableUserInteraction(): void
		{
			// Check if interaction is already disabled
			if (!isInteractionEnabled) return;

			// Save the information about the current focused component
			focusState = new Object();

			if (_managedApp.focusManager != null)
			{
				focusState.focusedComponent = _managedApp.focusManager.getFocus();

				if (focusState.focusedComponent != null &&
					focusState.focusedComponent.hasOwnProperty("selectionBeginIndex") &&
					focusState.focusedComponent.hasOwnProperty("selectionEndIndex"))
				{
					// Save the selection information about the focused component (useful for text
					// selection inside a TextInput for example).
					focusState.focusedCompSelectionBeginIndex = focusState.focusedComponent.selectionBeginIndex;
					focusState.focusedCompSelectionEndIndex = focusState.focusedComponent.selectionEndIndex;
				}
			}

			// Set the size of the blocker
			_blocker.width = _managedApp.width;
			_blocker.height = _managedApp.height;

			// Make the blocker the topmost component in the display list
			var rawChildren: IChildList = _managedApp.systemManager.rawChildren;

			if (rawChildren.contains(_blocker))
			{
				rawChildren.removeChild(_blocker);
			}

			rawChildren.addChild(_blocker);

			if (_managedApp.stage != null)
			{
				// Remove the focus from the current focused component
				_managedApp.stage.focus = null;
			}

			if (_managedApp.systemManager is DisplayObjectContainer)
			{
				// Disable tabbing so the user cannot use the tab key to cycle
				// among the components.
				focusState.sysManTabChildren = (_managedApp.systemManager as DisplayObjectContainer).tabChildren;
				(_managedApp.systemManager as DisplayObjectContainer).tabChildren = false;
			}
		}

		/**
		 * Restore the user interaction with the application.
		 */
		public function restoreUserInteraction(): void
		{
			// Check if the interaction is already enabled
			if (isInteractionEnabled) return;

			if (_managedApp.systemManager is DisplayObjectContainer)
			{
				// Restore the tabbing state saved before disabling the user interaction
				(_managedApp.systemManager as DisplayObjectContainer).tabChildren = focusState.sysManTabChildren;
			}

			// Remove the blocker from the display list
			var rawChildren: IChildList = _managedApp.systemManager.rawChildren;

			if (rawChildren.contains(_blocker))
			{
				rawChildren.removeChild(_blocker);
			}

			if (focusState.hasOwnProperty("focusedComponent") &&
				focusState.focusedComponent != null &&
				_managedApp.focusManager != null)
			{
				// Check if I can restore the focus or not depending on whether or not there
				// are modal popups over the previously focused component.
				var canRestoreFocus: Boolean = false;

				if (_managedApp.systemManager.numModalWindows > 0)
				{
					// Get the list of all the active popups
					var popupList: ArrayCollection = PopUpUtils.getAllPopups(_managedApp, true);

					if (popupList.length == 0)
					{
						// There are no popups, so I can restore the focus
						canRestoreFocus = true;
					}
					else
					{
						if (focusState.focusedComponent is UIComponent)
						{
							// Get the topmost popup
							var topmostPopup: Object = popupList.getItemAt(popupList.length - 1);

							var currParent: Object = (focusState.focusedComponent as UIComponent).parent;

							// Go through all the parents hierarchy for the component that should be
							// focused to check if it belongs to the topmost popup.
							while (currParent != null)
							{
								if (currParent == topmostPopup)
								{
									// The component that should be focused belongs to the topmost popup,
									// so I can restore the focus.
									canRestoreFocus = true;
									break;
								}

								if (currParent == currParent.parent)
								{
									break;
								}

								currParent = currParent.parent;
							}
						}
						else
						{
							canRestoreFocus = true;
						}
					}
				}
				else
				{
					// There are no modal popups, so I can always restore the focus
					canRestoreFocus = true;
				}

				if (canRestoreFocus)
				{
					// Restore the focus on the component that was focused before disabling the
					// user interaction.
					_managedApp.focusManager.setFocus(focusState.focusedComponent);

					if (focusState.focusedComponent.hasOwnProperty("selectionBeginIndex") &&
						focusState.focusedComponent.hasOwnProperty("selectionEndIndex"))
					{
						// Restore the selection inside the focused component (useful for TextInput
						// for example).
						focusState.focusedComponent.selectionBeginIndex = focusState.focusedCompSelectionBeginIndex;
						focusState.focusedComponent.selectionEndIndex = focusState.focusedCompSelectionEndIndex;
					}
				}
			}

			focusState = null;
		}
	}
}

This is the UserInteractionManager class and it manages all the necessary operations for you to disable and restore the user interaction. The constructor accepts the application that has to be managed by an instance of the class, so you’ll have a single instance of UserInteractionManager for an application. There are two functions in the class, disableUserInteraction and restoreUserInteraction.

When you decide to disable the interaction, UserInteractionManager saves the information about the current focused component so the focus can be restored later, then it puts a blocker canvas on top of every other child object in the application. Here we must use the rawChildren because the blocker must be also on top of the popups if present. After saving state information about the focused component and displaying the blocker, the focus is removed from the focused component and the tabChildren property of the systemManager is set to false so we ensure that the user cannot try to focus the components with the tab key. The blocker is not visible to the human eye because we set a very low backgroundAlpha value, but we must fill it with a color to make sure that the Flash player intercepts the mouse clicks on the blocker canvas instead of letting them go through the underlying components.

If you decide to restore the user interaction, then UserInteractionManager restores the tabChildren property of the systemManager, removes the blocker canvas and restores the focus on the previously focused component. While restoring the focus, we must also check if there are modal popups over the previously focused component. If the component is not a child of a topmost modal popup then it makes no sense to restore the focus on a component that is not supposed to have it since there’s a modal popup in front of it. To get all the popups in the application we use an utility class named PopUpUtils that we’ve already seen in a previous post. The properties selectionBeginIndex and selectionEndIndex are used with a TextInput or similar components to restore the text selection inside the focused component if some text was selected before disabling the user interaction.

Let’s take a look at an example application that uses the UserInteractionManager class. Read the rest of this entry »

Beware of singleton in Flex modules

Flex Published on March 12, 2010 by Andrea Bresolin 3 Comments »

Example 1 (without importing the singleton class in the main application – module-wide singleton):

Live demoSource code (LICENSE)

Example 2 (singleton class imported in the main application – application-wide singleton):

Live demoSource code (LICENSE)

This is something I recently discovered during some tests and it’s something to consider when using the singleton design pattern inside Flex modules. First of all, here is an example implementation of the singleton pattern in Flex:

public class SingletonClass
{
	protected static var _instance: SingletonClass = null;

	public static function getInstance(): SingletonClass
	{
		if (_instance == null)
		{
			_instance = new SingletonClass();
		}

		return _instance;
	}
}

This class can be simply used to get the singleton instance with a line like this:

var theInstance: SingletonClass = SingletonClass.getInstance();

This is what we already knew. But what could happen if we try to get a singleton instance inside a Flex module? It could happen that our SingletonClass represents in fact a singleton in two different ways: application-wide singleton or module-wide singleton. In the application-wide case, the instance of SingletonClass is unique across the entire application that uses some Flex modules, while in the module-wide case, the instance in unique only inside a single module, but different across different modules. This is really important to know because we may have undesired behaviors of our application and it could be difficult to figure out what happens without knowing this.

Now, the question is: how do we know when we have an application-wide singleton instead of a module-wide singleton? You may have guessed the answer from the examples links at the beginning of this post. We have an application-wide when the SingletonClass is imported in the main application while we have a module-wide singleton when the SingletonClass is used only inside the modules and never imported in the main application. An example will be useful to clarify everything. Read the rest of this entry »

Reducing Flex compilation time with an assets module

Flex Published on February 28, 2010 by Andrea Bresolin No Comments »

Example 1 (normal embeds):

Live demoSource code (LICENSE)

Example 2 (assets module):

Live demoSource code (LICENSE)

Some time ago one of my coworkers pointed me to a blog post that was giving suggestions to reduce the compilation time of a Flex project. Since we had long compilation times for our project at work, I decided to give it a try. The option that I chose was putting all the embeds inside a Flex module instead of embedding the assets directly inside each single source file. So, before testing the solution on the big project, I prepared a couple of small sample applications to test the difference and see if it was worth trying.

First of all, let’s briefly talk about the problem. Flex compiler can become slow if it has to embed a lot of assets in the application. This can be an issue if the application is particularly big. It seems that even if you change a single source file, the assets have to be embedded again to recompile everything. So, how can we avoid this? Using an assets module, and I’m going to call this module AssetsModule (quite straightforward).

In a standard application, when you want to embed an asset you have something like this:

<mx:Image source="@Embed(source='assets/myimage.png')"/>

With the usage of an assets module, you will have something like this:

<mx:Image source="{ModulesManager.getInstance().assets.myimage}"/>

To make our solution work, we need to make sure that there are no dependencies between the class that contains all the embeds in the module and the normal classes of the application. An interface is the right choice to achieve our goal. Read the rest of this entry »

Filtering the children of a Flex container

Flex Published on January 5, 2010 by Andrea Bresolin No Comments »
Live demoSource code (LICENSE)

In this post I’m going to show an utility function that I implemented some time ago. Its purpose is to filter the children of a Flex container. So, for example, let’s say that you want to have all the children of a specific container going deep throughout the entire children hierarchy, but you want to exclude some classes or instances from the search, then this function is for you. I use it to selectively enable or disable some components or to get the value of a specific property for them, but the function is generic enough to be used in many different situations.

The function is called getContainerChildren. Here is its source code:

package com.devahead.utils
{
	import mx.collections.ArrayCollection;
	import mx.core.Container;

	public class MiscUtils
	{
		/**
		 * Filters all the children of a container.
		 *
		 * @param container
		 *         Container of the children that have to be filtered.
		 * @param childrenClasses
		 *         Array of the classes that have to be kept while
		 *         filtering the children. If not specified, the type
		 *         of the children is not considered while filtering.
		 * @param excludedClasses
		 *         Array of the classes that have to be excluded.
		 *         The children must not belong to these types.
		 * @param excludedInstances
		 *         Array of the instances that have to be excluded.
		 *         The children must not be one of these instances.
		 * @param deepSearch
		 *         If true, specifies that the children must be
		 *         searched throughout the entire hierarchy util
		 *         there are no more children available for a
		 *         component. If false, only the children of the
		 *         container are considered and not their children.
		 * @param forceDeepSearchOnExcludedClasses
		 *         If true and also deepSearch is true, then the children
		 *         are searched also within the components that have been
		 *         excluded from the results because their type is among
		 *         the excludedClasses. If false, the children are never
		 *         searched within the excluded components. If a component
		 *         has been excluded because it's in excludedInstances, then
		 *         a deep search is never executed on it, even if it belongs
		 *         to an excluded class and forceDeepSearchOnExcludedClasses
		 *         is true.
		 * @param forceDeepSearchOnExcludedInstances
		 *         If true and also deepSearch is true, then the children
		 *         are searched also within the components that have been
		 *         excluded from the results because they are among
		 *         the excludedInstances. If false, the children are never
		 *         searched within the excluded components.
		 * @param resultArray
		 *         Array used to store the children found in the recursive
		 *         calls. It should be left null when the function is called
		 *         externally (not recursively).
		 * @return Array of the container's children filtered according
		 *         to the specified parameters.
		 */
		public static function getContainerChildren(container: Container,
			childrenClasses: Array = null, excludedClasses: Array = null,
			excludedInstances: Array = null, deepSearch: Boolean = false,
			forceDeepSearchOnExcludedClasses: Boolean = false,
			forceDeepSearchOnExcludedInstances: Boolean = false,
			resultArray: ArrayCollection = null): ArrayCollection
		{
			var componentsArray: ArrayCollection = (resultArray != null ?
				resultArray : new ArrayCollection());

			if (container != null)
			{
				// Check all the container's children
				for (var i: int = 0; i < container.numChildren; i++)
				{
					var currChild: Object = container.getChildAt(i);

					var isCorrectComponent: Boolean = false;

					// Check if the type of the current child is correct
					if (childrenClasses == null || childrenClasses.length == 0)
					{
						isCorrectComponent = true;
					}
					else
					{
						for each (var currClass: Class in childrenClasses)
						{
							if (currChild is currClass)
							{
								isCorrectComponent = true;
								break;
							}
						}
					}

					// Check if the current child is an instance that has to be excluded
					var excludedAsInstance: Boolean = false;

					if (excludedInstances != null && excludedInstances.length > 0)
					{
						for each (var currExcInst: Object in excludedInstances)
						{
							if (currChild == currExcInst)
							{
								isCorrectComponent = false;
								excludedAsInstance = true;
								break;
							}
						}
					}

					// Check if the current child's type has to be excluded
					var excludedAsClass: Boolean = false;

					if (excludedClasses != null && excludedClasses.length > 0)
					{
						for each (var currExcClass: Class in excludedClasses)
						{
							if (currChild is currExcClass)
							{
								isCorrectComponent = false;
								excludedAsClass = true;
								break;
							}
						}
					}

					// Check if I must use a deep search
					var mustGoDeeper: Boolean = (
						(excludedAsInstance && forceDeepSearchOnExcludedInstances) ||
						(!excludedAsInstance && excludedAsClass && forceDeepSearchOnExcludedClasses));

					if (deepSearch && (currChild is Container) &&
						((!excludedAsInstance && !excludedAsClass) || mustGoDeeper))
					{
						// Get all the children of the current child through a recursive call.
						//
						// NOTE: I don't need to care about the result value of the recursive
						//       call because the children found are directly inserted into the
						//       componentsArray variable.
						getContainerChildren(currChild as Container, childrenClasses,
							excludedClasses, excludedInstances, deepSearch,
							forceDeepSearchOnExcludedClasses, forceDeepSearchOnExcludedInstances,
							componentsArray);
					}

					if (isCorrectComponent)
					{
						// Add the child to the result list
						componentsArray.addItem(currChild);
					}
				}
			}

			return componentsArray;
		}
	}
}

The function is recursive, so during every recursion all the children of a container are discovered and they are filtered according to the specified exclusion classes or instances. If we must go deeper to find other components, then another recursion step is executed. Read the rest of this entry »

Getting all the popups in a Flex application

Flex Published on December 19, 2009 by Andrea Bresolin No Comments »
Live demoSource code (LICENSE)

In Flex, you can create popups easily, but what if you want to get all of them after they’ve already been created? You could keep track of every created popup using a customized function that puts every single instance in an array for example, but what if you’re using a Flex component that simply creates popups in its own way and you cannot keep track of what it creates? Here I’m going to provide a possible solution.

After some debugging, I found out that Flex puts all the popups among the rawChildren in the application’s SystemManager. This is where we can find them. So now that we know where to look, we need a way to distinguish the children that are popups from those that are not (rawChildren does not contain only popups). If we use only components whose base class is the standard UIComponent class (I think this is the case most of the times), there’s an easy way to know if an instance is a popup or not: the isPopUp property of UIComponent.

Whenever we create a new popup that extends UIComponent, the PopUpManager sets the isPopUp property to true. So, all we need to do is cycle through the application’s systemManager.rawChildren and check whether we find an UIComponent instance whose isPopUp property is true. In that case, we’ve got an application’s popup.

To demonstrate the concept, I’ve implemented the PopUpUtils class. It simply allows you to get all the popups inside an application instance, to discover if there are visible popups and to close all the popups. Let’s take a look at it. Read the rest of this entry »

Dynamic ObjectProxy

Flex Published on December 6, 2009 by Andrea Bresolin 2 Comments »
Live demoSource code (LICENSE)

The problem: I’ve got a Flex class with all its properties well defined. It’s good for me, it has all the properties I need to represent correctly the model, but sometimes I wish I had a few more properties to use it in some contexts. These additional properties are not strictly related to the model I want to represent, so I don’t want to add them to the class, but I need them to easily integrate with Flex components functionalities for user interaction.

The solution: DynaObjectProxy!

Before looking through the source code of DynaObjectProxy, let’s talk briefly about what it does. Basically, it’s a sort of ObjectProxy, but it extends its functionalities.

With ObjectProxy you can wrap a class instance and access to its properties through the proxy

// MyClass contains the property "prop1"
var myClassInstance: MyClass = new MyClass();
myClassInstance.prop1 = "The value";

var myProxy: ObjectProxy = new ObjectProxy(myClassInstance);

trace(myProxy.prop1); // Outputs "The value"

but you cannot dynamically create new properties in the ObjectProxy instance

trace(myProxy.prop2); // ERROR! "prop2" doesn't exist in MyClass

Otherwise, you can create an ObjectProxy instance without wrapping a class instance and in this case you actually can create new properties in the ObjectProxy

var myProxy: ObjectProxy = new ObjectProxy();
myProxy.prop2 = "The property value";

trace(myProxy.prop2); // Outputs "The property value"

What if I would like to have both the functionalities? DynaObjectProxy allows exactly this: you can both wrap a class instance and create new properties keeping all the new properties bindable at the same time.

Now we can start looking through the DynaObjectProxy source code and later we’ll see how it can be used with an example. Read the rest of this entry »

Multiple validators on a single component

Flex Published on November 29, 2009 by Andrea Bresolin 8 Comments »
Live demoSource code (LICENSE)

Sometimes, while using validators in Flex, i needed to have more than one validator connected to a single component, e.g. a TextInput. So, at the beginnig, I tried the naive approach, just create multiple validators and assign to all of them the same source and the same property to validate. After a few tests, I quickly realized that in Flex, a single component is meant to have only one validator associated to it. This is a problem in some situations because I have different validatiors that already do what I need and I just want my component to be considered valid only when all the validators are valid. So I investigated more in depth taking a look at the Flex SDK source code and I realized that it’s by design that I simply cannot do it easily. What usually happens is that it’s the last triggered validator that decides if a component is valid or not. We know that everything is based on events dispatching in Flex and that we cannot know the order in which events reach a particular component, so we also don’t know what will be the last validator to be triggered for a component. This is especially evident when a form is quite complex and contains a lot of fields that have to be validated.

What can we do to solve this problem? Here I’m going to explain what I did about a couple of years ago, when I faced this problem. There are rumors that there should be something available in the next version of the Flex SDK (version 4) that solves the problem, but meanwhile, we can still solve it using the manager class I developed. I’ve been using it up until now and it always worked as expected without problems. Basically, the class takes care of all the validation events coming from different validators and makes sure that the right validity state is preserved for the component that has been validated. It doesn’t matter when the events are dispatched, it’s not important, the final result is:

  • a component is considered VALID if all the validators say that it’s valid;
  • a component is considered INVALID if at least one of the validators says that it’s not valid.

Let’s take a look at the source code now. Read the rest of this entry »

WP Theme & Icons by N.Design Studio
©2009-2010 Andrea Bresolin. All rights reserved. - Privacy Policy
Entries RSS Comments RSS