Flex popup window - actionscript-3

I am creating modal popup canvas window in a parent page. When I close the popup how do we get notification in parent screen that child popup is just closed. Any event for that ?

The code to show your popup:
var popup:MyPopup = new popup:MyPopup();
popup.addEventListener(CloseEvent.CLOSE, function(evt) {
PopUpManager.removePopUp(popup);
});
PopUpManager.addPopUp(popup, this, true);
Inside your MyPopup class, you will have a button for closing the popup. Simply hook the click event to publish a "CLOSE" event:
<s:Button Label="X" click="dispatchEvent(new CloseEvent(CloseEvent.CLOSE));" />
I prefer this mechanism over having the MyPopup object calling PopUpManger.removePopUp (as #Fank is suggesting) because it couples the MyPopup component to the PopUpManager which I don't like. I'd prefer the user of MyPopup to decide how to use the component.
Honestly, though, these are two very similar mechanisms to perform the same end goal.

Yes there is:
I Preffer to use the Popupmanager:
Your Popup:
There is a Button "close" call a internal function eg.closeme
private function closeMe () :void
{
PopUpManager.removePopUp(this);
}
in your Parent, you open the PopUp like this:
private function openPopup () :void
{
var helpWindow:TitleWindow = TitleWindow(PopUpManager.createPopUp(this,MyTitleWindow,fale));
helpWindow.addEventListener(CloseEvent.CLOSE, onClose);
}
protected function onClose (event:CloseEvent) :void
{
PopUpManager.removePopUp (TitleWindow(event.currentTarget));
}
My TitleWindow is the name of your class of cour popup extended by TitleWindow.
BR
Frank

Along with Brian's answer don't forget to detach the event listener. If you leave the event handler in your main app listening for an event from a child object, the child object will not be garbage collected as something is still referencing it. This is a common memory leak issue.
popup.addEventListener(CloseEvent.CLOSE, popup_CloseHandler);
private function popup_CloseHandler(event:CloseEvent):void{
event.target.removeEventListener(CloseEvent.CLOSE, popup_CloseHandler);
PopUpManager.removePopUp(popup);
}
Here's a great post about Flex's memory management if you want to delve into that further.
http://blogagic.com/163/flex-memory-management-and-memory-leaks

Related

Alert/ Dialog box in AS3

I am working on a app using Adobe flash Builder which should pop up a Alert window once a particular event has been triggered.
Another event needs to be called when the Alert box is closed. But I do not see the Alert class in mx.controls library. It seems like the class (which existed in AS2) has been removed from AS3. Is there any other way to accomplish the same functionality?
Thanks,
Pritesh
Yo need to define closeHandler for your Alert control. Checkout the ActionScript 3.0 Reference api from here http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Alert.html#show()
Use ExternalInterface.
import flash.external.ExternalInterface;
// tell flash what javascript function to listen for, and what flash function to call in response
ExternalInterace.addCallback('onAlertWindowClosed', onPopupClosed);
function openPopUp():void
{
// this conditional prevents errors when running local (yes, this needs uploaded to work)
if(ExternalInterface.available)
{
// this calls a javascript function in your html
ExternalInterface.call('myJavascriptAlertFuntion');
}
}
// this function is called from the javascript callback **onAlertWindowClosed**
function onPopupClosed():void
{
// do something when your popup closes
}
and in the html:
<script type="text/javscript>
// this chunk gets the flash object so you can call its methods
function getFlashMovieObject(movieName)
{
if (window.document[movieName])
{
return window.document[movieName];
}
if (navigator.appName.indexOf("Microsoft Internet") == -1)
{
if (document.embeds && document.embeds[movieName])
return document.embeds[movieName];
}
else
{
return document.getElementById(movieName);
}
}
// function that is called from flash
function myJavascriptAlertFuntion()
{
alert("Hey! Yeah you there!");
}
// call this when you want to tell flash you are closing your popup
function tellFlashMyPopupWindowClosed()
{
// **flashContainer** should be replaced by the name parameter of your flash embed object
var flashMovie = getFlashMovieObject("flashContainer");
flashMovie.onAlertWindowClosed();
}
</script>
To have a popup alert in a Mobile project using MXML and AS3, you need to create a component based off of the SkinnablePopUpContainer from the Sparks components. (Since a simple alert has been conveniently uncluded.)
I learned alot reading up on the SkinnablePopUpContainer in the docs here:
The Spark SkinnablePopUpContainer container
To sum it up, I've created a component in MXML with SkinnablePopUpContainer as the base class. In the View that I want to have the popup to be added to, I create a new instance of the class in Actionscript. I listen to the custom events the buttons in the component will be firing on user response. To show the new popup component, simply call the static method open();. The open() method expects a parent container, and wether or not the popup should be Modal. Modal means that nothing under the component can receive user input.
var alert:SkinnablePopUpContainer = new SkinnablePopUpContainer;
alert.addEventListener( "OK", onOK );
alert.open( this, true );
function onOK(e:Event):void{ trace("User said OK") };
I'll put up some example files later when I can.

I need help bubbling an event in AS3

I want to have the parent of my class handle the event first, then I want to have the child handle the event. Is there a way to explicitly bubble the event up? I want to do something like this:
...
this.addEventListener(MouseEvent.CLICK, characterClicked);
...
private function characterClicked(e:Event):void{
// pass event to parent to be handled first
...
}
Is this possible, and if so how?
There are three "phases" of an event; Capture, At target and Bubble. They occur in this order, meaning that if you set an event listener to be in the capture phase it will always fire before one set regularly (which would mean either at target or bubble).
Like so:
// in parent, third argument is "use capture"
child.addEventListener(MouseEvent.CLICK, handleClickInParent, true);
// in child, add listener as usual
addEventListener(MouseEvent.CLICK, handleClick);
Now, your parent event listener will always fire first!
I figured out a way to do this. Is seems hackish, but it works. If there is a better way of doing this please let me know.
...
this.addEventListener(MouseEvent.CLICK, characterClicked);
...
private function characterClicked(e:Event):void{
// pass event to parent to be handled first
this.removeEventListener(MouseEvent.CLICK, characterClicked); //prevent infinite loop
dispatchEvent(e); // send event to parent object
this.addEventListener(MouseEvent.CLICK, characterClicked);
e.stopImmediatePropagation();
...
}
If you were to handle the listener in the parent instead of the child it might be easier. Then you could just pass the event to the child when you're done:
// inside parent class:
childObj.addEventListener(MouseEvent.CLICK, onCharacterClicked);
private function onCharacterClicked(e:Event):void {
// do parent stuff first
// ...
// then pass event to child
childObj.onCharacterClicked(e);
}

Event listener to keyboard event not listening in a module

I am doing this inside a module containing viewstacks and their childs.
Calling onInit() on creationComplete of module.
When I am inside one of the childs of a viewstack of this module and press Enter, it doesnt not invoke the listener function at all (bp inside this does not get hit).
private function onInit():void{
this.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
}
private function keyPressed(evt:KeyboardEvent):void
{//this breakpoint never gets hit on pressing a key in screen
if (evt.keyCode == Keyboard.ENTER)
{
//do this
}
}
You should add key listeners to stage objects:
private function onInit():void{
this.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
}
This can be very frustrating as there are a few different things that can affect this.
1) Add your event listeners at the appropriate place. The code that you have there is fine for capturing, just ensure it is in the parent or above of where the events are being fired.
2) You need to ensure you have focus. This is usually the issue people run into and it's in the docs but not immediately clear. If you look at the live doc link here and do a search for setFocus() - you'll notice that it is in every one of their examples (except top, which is broken!) - yet, they don't ever mention it in the actual documentation on the page.
http://livedocs.adobe.com/flex/3/html/help.html?content=events_11.html
So, even in their first example, if you click into the app (and not the textbox), it wont work!
<?xml version="1.0"?>
<!-- events/TrapAllKeys.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp();">
<mx:Script><![CDATA[
private function initApp():void {
application.addEventListener(KeyboardEvent.KEY_UP, keyHandler);
}
private function keyHandler(event:KeyboardEvent):void {
t1.text = event.keyCode + "/" + event.charCode;
}
]]></mx:Script>
<mx:TextInput id="myTextInput"/>
<mx:Text id="t1"/>
</mx:Application>
If however, you set focus yourself by changing the init function like this, it will!
private function initApp():void {
application.addEventListener(KeyboardEvent.KEY_UP, keyHandler);
myTextInput.setFocus();
}
Another trick for testing if this is your problem is to add a textbox as a child of the container that has the capturing, if they magically work after you click in that text box - its a focus problem indeed!
=)

Is it possible to remove an eventListener temporarily (i.e. until a function has been executed)

I am doing actionscript 3 at the moment and was wondering if it was possible to remove and eventListner temporarily. I know of removeEventListener, however, that removes the eventListener completely and i cannot click the button again.
If you want some more details, here the exact problem. I have function that when a button is pressed, an object appears. In the function which makes this object there is an eventListener which leads to a function which allows the user to press that object. When you press that object it disappear and the button will animate. However, since the original eventListener still exists, you can press the object while in motion and create a new object. So to the point: What i want to do is disable the eventListener while the button is moving, and reactivate it when it stops.
The best way is to simply use a flag which tells the function if the animation is complete or not. Here's an example of what I'm talking about using TweenLite as tween library:
public class CreateButton extends Sprite{
private var animating:Boolean = false;
public function CreateButton(){
this.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
}
private function onClick(event:MouseEvent):void{
if(this.animating == false){
// Trigger creation functionality
TweenLite.to(this, 0.5, {/* Parameters for the actual animation */ onComplete:animationComplete});
this.animating = true;
}
}
private function animationComplete():void{
this.animating = false;
}
}
It is best practice to remove the listener if it's functionality is to be disabled. You could however set the .mouseEnabled to false if you want to disable it's click functionality without removing the listener.

Flex event handler not working

I have created a custom event in flex 3.5. But the handler is not invoked. How to solve this or what is the way to debug this problem?
The Event class:
package com.saneef.worldlanguages.events
{
import flash.events.Event;
public class LanguageEvent extends Event
{
public static const LANGUAGE_SELECTED:String = "LanguageSelected";
public function LanguageEvent(type:String,languageid:String)
{
super(type);
this.langid = languageid;
trace("LanguageEvent: " + this.langid);
}
public var langid:String;
override public function clone():Event {
return new LanguageEvent(type, langid);
}
}
}
Dispatching:
private function functionOne():void
{
try{
dispatchEvent(new LanguageEvent(LanguageEvent.LANGUAGE_SELECTED,"STR"));
}
catch(e:Error)
{
trace(e.message);
}
}
In the Main application class, EventListener:
protected function application1_initializeHandler(event:FlexEvent):void
{
this.addEventListener(LanguageEvent.LANGUAGE_SELECTED,
application1_LanguageSelectionHandler);
}
The event handler function:
public function application1_LanguageSelectionHandler(event:LanguageEvent):void
{
trace("application1_LanguageSelectionHandler: " + event.langid);
populate_countrya3id_languages(event.langid);
}
Your code looks fine. Since I can't see the full source, here are my two thoughts on what may be going on:
Are you sure your addEventListener call is done before you dispatch the event? Add some trace to make sure the application1_initializeHandler prints before functionOne does.
Is your functionOne call in another different component than your main application? If so, you'll need to set your custom event's bubbles attribute to true in your event's super call.
public function LanguageEvent(type:String,languageid:String,bubbles:Boolean=True)
{
super(type, bubbles);
this.langid = languageid;
trace("LanguageEvent: " + this.langid);
}
See the flash.events.Event docs for the constructor call. Also, here's a quote about the bubbles argument explained here:
The bubbles property
An event is said to bubble if its
event object participates in the
bubbling phase of the event flow,
which means that the event object is
passed from the target node back
through its ancestors until it reaches
the Stage. The Event.bubbles property
stores a Boolean value that indicates
whether the event object participates
in the bubbling phase. Because all
events that bubble also participate in
the capture and target phases, any
event that bubbles participates in all
three of the event flow phases. If the
value is true, the event object
participates in all three phases. If
the value is false, the event object
does not participate in the bubbling
phase.
Based on your source code, it looks like you've seen the "Dispatching Custom Events" in the flex docs, but I'll link to it anyways for future/easy reference: http://livedocs.adobe.com/flex/3/html/help.html?content=createevents_3.html.
Also, check out http://www.adnandoric.com/2008/12/29/understanding-the-flex-event-propagation/ for a high-level overview of the event propagation system to try to get a better understanding of what's going on while developing.
Edit:
Based on your comments I'm guessing your functionOne call is in a separate class and your "main" application has an instance of this class. If that's so you'll want to attach your event listener on that instance and delegate it to your main's application1_LanguageSelectionHandler function... Like so:
protected function application1_initializeHandler(event:FlexEvent):void
{
this.theInstanceThatHoldsYourFunctionOne.addEventListener(LanguageEvent.LANGUAGE_SELECTED,
application1_LanguageSelectionHandler);
}