Recent Posts

Events with non-DisplayObjects in the Mate Flex framework

So I was loving the MVC framework Mate, but started to run into issues trying to figure out best-practices for dispatching and handling events.

Researching:

1) How you dispatch events from non-view parts of your Flex Mate app

2) Is this a good practice and what is the best practice for using events in Mate with regards to loading an app’s data from a remote source and handling server data?

Results:

1) In a non-DisplayObject, don’t just use dispatchevent(), but you need to instantiate a Mate dispatcher.

At the top make sure you import the class.

import com.asfusion.mate.events.Dispatcher;

Then:

var myDispatcher:Dispatcher = new Dispatcher();
var qlEvt:QuotesLoadedEvent = new QuotesLoadedEvent(QuotesLoadedEvent.QUOTES_LOADED, true);
myDispatcher.dispatchEvent(qlEvt);

This worked for me. I was dispatching the event from a QuoteManager that was responding to the result of a RemoteObject call. But it seems that the listening component (a Box with a datagrid) would only hear the event when I did the following in an injector tag (target=”{QuoteGrid}”) in the eventMap:

<ListenerInjector method="resetQuotes" eventType="{QuotesLoadedEvent.QUOTES_LOADED}"/>

If I used:

<EventHandlers type="{QuotesLoadedEvent.QUOTES_LOADED}">
<MethodInvoker generator="{QuoteGrid}" method="resetQuotes"/>
</EventHandlers>

The QuoteGrid component did not hear the event.

2)TBD

See: http://mate.asfusion.com/page/documentation/tags/dispatcher

The main issue was dealing with events that were being launched from a Manager class, which was handling a remote response from php. After the response, in the manager, I was firing a custom Event that signaled the initial data had been loaded for the app, and then trying to listen for this data_loaded event to signal to the view to update the display (wasn’t a simple property injection since the display had filters, etc. which was making the data layer far more complex with a filteredArray, etc.).

This post: http://mate.asfusion.com/forums/topic.php?id=317 was helpful, when I realized why the hell my eventmap was not able to assign a responsive listener for the data_loaded event. The event was being fired from a Manager class, but nothing was listening or responding and I guess that is because the event map doesn’t handle events dispatched from non-DisplayObjects (like my QuoteManager).

So what is the best practice for notifying views that data has been loaded, when I cannot relying on simple property injection to get the data from the Manager to the view? TBD. Also, is injecting a listener int the eventMap the same as handling an event and invoking a method in the eventMap?

I want to 1) get a bunch of stock quotes for a dataGrid 2)After the data has been received, send it to the view, and not just update a property on the view but copy the data into various other properties so I can manipulate the data on the view with several filters and preserve the original state of the master ArrayCollection. I wonder if using expanded getters/setters on the original/master stock ArrayCollection and its source will be necessary. I would love to see some clear documentation on manipulating/filtering ArrayCollections and what happens to the Array source when the filter function is set.

I would also like to figure out a best-practice for handling server data, and responding to this data using the model concept of MVC and events in Mate. The documentation so far has been good, but not clear on how to accomplish the aforementioned goal.

Cruise Control and/or ANT out of memory error

When setting up a flex app auto build task, I started getting the following error consistently.

Error: null
java.lang.OutOfMemoryError

THE FIX, for me was: Add to ant.bat, antRun.bat

set ANT_OPTS=-Xmx512m
set ANT_OPTS=-Xms64m -Xmx512m

First I tried changing the Cruise Control memory settings in cruisecontrol.bat (CC_OPTS=-Xms256m -Xmx768m -Xmn256m).But I think it was less likely for the cruise control process to have memory issues than the ant tasks I was using (as Jeffrey pointed out before I could clean this up a bit – thanks).

I was noticing that the java.exe service that was handling the process would go up to 100 MB of memory usage, and then stop there, and then tank. The following article points out how to change the ant task memory settings. Because of the way cruise control was calling the ant task, it made it necessary to modify the the .bat files in the ant folder (You can use the <ant><jvmarg>… tag, as per the links below, in some cases). Once the .bat’s had the ANT_OPTS memory settings in place, the process would use more memory and build the flex app. Nice.

Check out the following articles:

http://confluence.public.thoughtworks.org/display/CC/OutOfMemoryError

http://cruisecontrol.sourceforge.net/main/configxml.html#ant

Flex Tree not allowing Drops

The Skinny

By using mx:Tree dropEnabled=”false” and registering the drag and drop listeners separately using the addEventListener Method with the use_capture parameter set to true, items could be consistently dropped from one control into the tree control. Otherwise, the drop was broken, not working many times, and the red ‘x’ disallowed drop feedback would persist, even when the drop should have worked.

I got it to work by changing
albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragEnter, false, 0, true);
TO
albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragEnter, true, 0, true);

Be sure and add DragManager.acceptDragDrop(UIComponent(event.currentTarget)); to the onDragEnter method (See links and discussion below).

Working with drag and drop in Flex Tree Controls

First – make sure you are following the adobe documentation, and the great advice found in the following article:

http://weblogs.macromedia.com/pent/archives/2006/11/tree_drag_and_d.html

On the adobe site, there is a great article about how to drop on to a tree control(Key here is dropEnabled has to be false on the tree, and you do your own drag and drop handling). This seemed to work better than the simpler example above where dropEnabled was true. I think relying on the default behaviors (dropEnabled=”true”) is kind of iffy, unless you are doing really simple stuff. Check the section ‘Dragging and Dropping to a tree control’ near the bottom:

http://www.adobe.com/devnet/flex/quickstart/working_with_tree/

The dropEnabled property of the tree component handles drag and drop in certain ways in which it makes it hard to override or use your own drag and drop event listening at the same time.

Also, if you have nested components and/or a more complex mxml interface, you may run into the following problem –

A flex tree nested in a few components was not accepting drops from a tileList nested in a few components. I think in traversing the components that the drag_enter precedence or firing was getting screwed up and not allowing drops. It would only accept drops sometimes. As you dragged over a VBox divider, the drop indicator (feedback) was showing a red x, and often, but not always, the red x would persist into the drop target the SHOULD have been allowing drops and drag enter. It was turning out that a slow drag would allow a drop, but a fast drag over to the drop target was not allowed, where the red x persisted.

Adding DragManager.acceptDragDrop(UIComponent(this)); where this is the parent container, just makes everything in the parent container accept a drop, which is not what I was looking to do. And it’s kludgey.

I got it to work changing albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragEnter, false, 0, true); TO albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragEnter, true, 0, true);

For some reason the use_capture parameter fixed this. The key (which I don’t posses yet) is in understanding the different phases of event processing. Capture, target, and bubble.

Adobe – “The use_capture parameter of the addEventListener() method lets you control the phase in the event flow in which your listener will be active. It sets the value of the useCapture property of the Event object. If useCapture is set to true, your listener is active during the capturing phase of the event flow. If useCapture is set to false, your listener is active during the targeting and bubbling phases of the event flow but not during the capturing phase. The default value is determined by the type of event, but is false in most cases.

To listen for an event during all phases of the event flow, you must call addEventListener() twice, once with the use_capture parameter set to true, and again with use_capture set to false. This argument is optional. For more information, see Capturing phase.”

Note – Changing the event priority higher didn’t work (albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragExit, false, 10, true);)

Blank Coldfusion errors on Query of Queries using like clause

[Macromedia][SQLServer JDBC Driver]Value can not be converted to requested type.

If you have a string column that contains a null value, this occurs. You have to add a check for the null first. Note that the like clause is also case sensitive for query of queries.

Breaks:

SELECT * FROM myTable
WHERE 1=1
AND LOWER(name) LIKE <cfqueryparam cfsqltype=”cf_sql_varchar” value=”%#LCase(searchCriteria.search)#%” />

Works:

SELECT * FROM myTable
WHERE 1=1
AND name is not null AND LOWER(name) LIKE <cfqueryparam cfsqltype=”cf_sql_varchar” value=”%#LCase(searchCriteria.search)#%” />

jQuery Dialog not showing content after being hidden

So the autoOpen:false on the jQuery dialog instantiation doesn’t hide the div fast enough sometimes. You can skirt this by setting the display to none (display:none) on the dialog div you made, but then when you actually do load up the dialog after someone clicks an anchor, or whatever, the content of the div doesn’t show up because the child divs have all inherited the display:none;

Just call the show method after the dialog load to skirt this.

$(“#detailPopin”).dialog(‘open’);
$(“#detailPopin”).show();

Flex Builder – Please specify a context-root compiler argument.

I don’t remember ever having to do this, but all of a sudden I needed to:

add ‘-context-root /’ to the Properties->flex compiler ->additional compiler arguments

The error was:

The services configuration includes a channel-definition ‘java-secure-http’ that has an endpoint with a context.root token but a context root has not been defined. Please specify a context-root compiler argument.

Error: ‘jQuery.event.special[…].teardown’ is null or not an object

Apparently, when the page is left, jQuery tries to remove event listeners. When this happens, the jQuery.event.special[type].teardown is null or undefined in a line of the jQuery source. This appears to be a dialog error, or caused by the dialog somehow. The jQuery error is found on line 1948 using the latest release, 1.2.6. (For me this is line 1955 but my jQuery has been a little modified).

I added the following to the if on line 1948 – || !jQuery.event.special[type].teardown. This fixes the jQuery error on line 1948.

if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem)
=== false ) {

becomes

if ( !jQuery.event.special[type] || !jQuery.event.special[type].teardown
|| jQuery.event.special[type].teardown.call(elem) === false ) {

This makes it so if the teardown function is undefined, an error won’t occur.

I am fairly certain that this fix doesn’t break anything else, but no guarantees. I didn’t spend a lot of time going into what elem.removeEventListener or elem.detatchEvent does because it looks like the eventListeners are not very consequential. Maybe a little bit more overhead. All I know is when I added the extra if, things worked great from that point on. And what I call a jQuery error could very well be an IE error, a user error (me, of course), etc. I happen to love jQuery.