Link to home
Start Free TrialLog in
Avatar of csciguy81
csciguy81

asked on

How do I make a function fire an event on a return, or make the rest of my application pause until this function returns?

Hello all, Actionscript newbie here.

I've got a function that is called when a button is clicked on a panel.  This function will contact a controller class, that in tern contacts a remote object (java servlet) to gather some data from a database.

I've noticed when I make this call, there seems to be no way for the system to "wait" for this entire process to wait until the call is done before it proceeds.  Is there a way to attach an event listener inside of my remote call on the actionscript side, such that when this event occurs, my program can continue on with the populated data?  Essentially what happens now is that the program continues on, and the data loads a few ms later.  I need the program to wait to get this data before proceeding, so I can populate the next form.  Is this a logical way to proceed, or should I look for another solution?

I've attached some code.  Hopefully it makes sense. Thanks all.
//this gets called when the button is pressed
private function TakeTest(event:MouseEvent):void{
if(incompleteList.selectedItem != null){
	questionController.TakeTest(incompleteList.selectedItem as Course);
	//need to figure out how to either pause here, or take the below and    handle it in another function when the TakeTest method finishes it's business.
	questionViewerPanel.enabled = true;
	questionViewerPanel.visible = true;
	questionViewerPanel.includeInLayout = true;
	questionViewerPanel.GetQuestionAndDisplay();
}
}
 
QuestionController.TakeTest is below:
 
public function TakeTest(courseToTake:Course):void{
			
       var ro:RemoteObject = new RemoteObject("questionSvc");
			
       var token:AsyncToken = ro.getQuestionsForCourse(courseToTake.name);
			
	token.addResponder(new ItemResponder(loadQuestions,onFault));
        	
}
		
private function loadQuestions(event:ResultEvent, token: AsyncToken = null) :void{
	for each(var obj:Object in event.result){
                var tObj2:Question = obj as Question;
                		//add item to array collection
                                  loadedQuestions.addItem(tObj2);
        }
        //I'd like to either return something here, back up to my original page, or fire an event here that I can listen out for.
                		
}

Open in new window

Avatar of zzynx
zzynx
Flag of Belgium image

Flex is all about events.

1) Make your loadQuestions() function throw a custom event (say QUESTIONS_LOADED)
2) Listen for it in your TakeTest function (cf attached code snippet)


All about Custom Events : http://livedocs.adobe.com/flex/3/html/help.html?content=createevents_1.html
private function TakeTest(event:MouseEvent):void{
   if(incompleteList.selectedItem != null){
          questionController.addEventListener(MyEvent.QUESTIONS_LOADED, function():void {
              questionViewerPanel.enabled = true;
              questionViewerPanel.visible = true;
              questionViewerPanel.includeInLayout = true;
              questionViewerPanel.GetQuestionAndDisplay();
          });
          questionController.TakeTest(incompleteList.selectedItem as Course);
   }
}

Open in new window

Avatar of csciguy81
csciguy81

ASKER

Can anything throw an event?  Even if it's some piece of embedded actionscript that is down inside of a controller?
ASKER CERTIFIED SOLUTION
Avatar of zzynx
zzynx
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Handling Events: http://learn.adobe.com/wiki/display/Flex/3b.+Handling%20Events
(and press the next button to see the demo)
So would my controller then need to extend Event?  The TakeTest function mentioned above lives on a flex component itself (just a simple panel with a button and some text).  The question controller itself is just an actionscript class.  Would that controller class need to extend Event?

The controller itself is nothing more than a collection of functions that provide remote object calls into my web service.
Update.  Here is my QuestionEvent class I wrote.  Now, how do I fire this off from inside of a function that lives inside of another class?


package Custom_Events
{
	import flash.events.Event;
 
	public class QuestionEvent extends Event
	{
		
		
		public function QuestionEvent(type:String, 
            isEnabled:Boolean=false) {
                // Call the constructor of the superclass.
                super(type);
    
                // Set the new property.
                this.isEnabled = isEnabled;
        }
 
        // Define static constant.
        public static const QUESTIONS_UNLOADED:String = "questionsUnloaded";
        public static const QUESTIONS_LOADED:String = "questionsLoaded";
 
        // Define a public variable to hold the state of the enable property.
        public var isEnabled:Boolean;
 
        // Override the inherited clone() method.
        override public function clone():Event {
            return new QuestionEvent(type, isEnabled);
        }
 
		
	}
}

Open in new window

I threw this inside of my function in the Question Controller that loads the questions.  It's however telling me, "call to a possibly undefined method dispatchEvent." and erroring out.


var questionEventObj:QuestionEvent = new QuestionEvent("questionsLoaded");
						questionEventObj.isEnabled=true;
						dispatchEvent(questionEventObj);

Open in new window

Concerning your own event, this is sufficient:

package Custom_Events {
      
      import flash.events.Event;

      public class QuestionEvent extends Event      {

                public static const QUESTIONS_UNLOADED:String = "questionsUnloaded";
                public static const QUESTIONS_LOADED:String = "questionsLoaded";

            public function QuestionEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) {
                  super(type, bubbles, cancelable);
            }
      }
}

>> So would my controller then need to extend Event?
No, EventDispatcher
>> It's however telling me, "call to a possibly undefined method dispatchEvent."
That's because it doesn't extends EventDispatcher
So,

public class YourControllerClass extends EventDispatcher {

   ...
   private function loadQuestions(event:ResultEvent, token: AsyncToken = null) :void{
        ...
       dispatchEvent( new QuestionEvent(QuestionEvent.QUESTIONS_LOADED, true /*bubbling*/) );
   }

}

and

private function TakeTest(event:MouseEvent):void{
   if(incompleteList.selectedItem != null){
          questionController.addEventListener(QuestionEvent.QUESTIONS_LOADED, function():void {
              questionViewerPanel.enabled = true;
              questionViewerPanel.visible = true;
              questionViewerPanel.includeInLayout = true;
              questionViewerPanel.GetQuestionAndDisplay();
          });
          questionController.TakeTest(incompleteList.selectedItem as Course);
   }
}
Let me make a correction.
The Flex API Doc says: "You are required to override the Event.clone() method in your subclass."
Why it's important to override clone in your custom Event class?
http://manishjethani.com/blog/2008/04/04/why-its-important-to-override-clone-in-your-custom-event-class/
http://www.allmas-tn.com/200810257/always-override-the-clone-method-for-your-custom-events.html
http://michaelangela.wordpress.com/2008/04/03/implement-clone-in-custom-events/
http://life.neophi.com/danielr/2006/06/events_in_flex_2.html

So to avoid problems later on, you'd better add that clone() function to your QuestionEvent class:
package Custom_Events {
      
      import flash.events.Event;
 
      public class QuestionEvent extends Event      {
 
            public static const QUESTIONS_UNLOADED:String = "questionsUnloaded";
            public static const QUESTIONS_LOADED:String = "questionsLoaded";
 
            public function QuestionEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) {
                  super(type, bubbles, cancelable);
            }
 
            override public function clone():Event {
                return new QuestionEvent(type, bubbles, cancelable);
            }
            
      }
}

Open in new window

Yeah, I saw in the docs that I needed to implement Clone, so I threw that in there.  Let me modify my QuestionController to extend EventDispatcher and I'll report back.  Thanks for the help so far.  Hopefully I'll be able to close this one out today.
Ok, I got something working, but I have one last question here in these regards.

Instead of having the QuestionController add an event listener, can I make the panel itself have one?  The panel in which the "TakeTest" function resides in has a few other functions inside of <mx:Script> tags that are used on the page itself (to control some loading, etc).  

If I say something like:
this.addEventListener(QuestionEvent.QUESTIONS_LOADED, function():void{//etc}
the listener never listens.

The "this", in this case, would be the component itself (Canvas) right?

If I say something like:
questionController.AddEventListener(QuestionEvent.QUESTIONS_LOADED, function():void){//etc}
the listener listens, everything works as expected.

Why is that?
>> If I say something like:
>> this.addEventListener(QuestionEvent.QUESTIONS_LOADED, function():void{//etc}
>> the listener never listens.
Well, it listens but it never "hears" something ;o)
By writing that, you listen for this (Canvas, Panel or whatever) to dispatch that kind of event.
But since we wrote our code in a way that the controller performs a dispatchEvent(...) we should listen on that one for the event.

Assume we have two person classes John and Pete.
If in John we perform a yell("Hello world");
then in we could write code like this:

var pete:Pete = new Pete();
pete.addListener(Yell, ....);

We listen for Pete to yell, while it's John we made yell at us. See?
Hmm.  Interesting.

I think I might have a somewhat better understanding now.  Thanks for the great help!
Great suggestive help.  Thanks a lot.
Glad I could help.
Thanx 4 axxepting