24 Replies Latest reply on Feb 21, 2007 10:26 AM by phi2265

    Can I have a function performed on application close?

    phi2265 Level 1
      I need a function to be called at the close of the application, how would I do this?

      I've created a database, using FDS, for users... and I need to have the user logged out when they close the window or in the database, their "Logged In" value is set to true.. and will remain true until set to false. Any ideas? Thanks!

        • 1. Re: Can I have a function performed on application close?
          FlightGuy
          There isn't an event in Flex that can tell you it's being killed.

          Two options I can see:
          a) use a keep-alive timer to send an HTTPService request every x seconds and let the server clean up expired sessions (not a bad idea anyway, since a client might vanish without getting a chance to tell you).
          b) In your html page, add an onbeforeunload event on the body tag. In this script, execute a function on your application...

          To do this, you can just call, for example, application.logOut() from script where application is the id of the object tag, and logOut is a public method in your flex application. If you want to force the user to save something first, for example, you can make a function

          public function logOut():Boolean{
          //do you server stuff
          //return false if you need to prevent the close, true if you want to let it happen
          }

          Then in your onbeforeunload javascript,

          function handleBeforeUnload() {
          if (!application.logOut) return "Please do something first";
          }

          <body onbeforeunload="return handleBeforeUnload()">...

          Tim
          • 2. Re: Can I have a function performed on application close?
            phi2265 Level 1
            I'm gonna try the keep-alive timer.. that sounds good to me.. that way i can keep it all in flex and not have to mess with the html. I'm not exactly sure how to get started on that.. could you point me in the right direction? thanks.

            • 3. Re: Can I have a function performed on application close?
              FlightGuy Level 1
              Sure -

              You can either do this in your application, or (my preference), make a class specifically for this. You can create an instance of the class in your application and let it do its own thing. You can make your class implement IMXMLObject - that way you can include it in your application's mxml. The class will create and start a timer, and will send an HTTPService request periodically. You can define an event if you like, which will be dispatched each time you get a response. This will allow your application to listen to it, and gives you a way to initiate contact from the server (which you can't do otherwise with http).

              Sorry this looses all its formatting - you'll have to copy it and reformat it (looking forward to when FlexBuilder can do that. I tried it and it seems to work fine:

              package com.spears.lang
              {
              import mx.core.IMXMLObject;
              import flash.events.EventDispatcher;
              import mx.rpc.http.HTTPService;
              import flash.utils.Timer;
              import flash.events.Event;
              import flash.events.TimerEvent;
              import mx.rpc.events.ResultEvent;
              import mx.rpc.events.FaultEvent;

              [Event(name="result", type="mx.rpc.events.ResultEvent")]
              [Event(name="fault", type="mx.rpc.events.FaultEvent")]
              public class KeepAlive extends EventDispatcher implements IMXMLObject
              {
              private var _url:String;
              private var _interval:int = 5000;
              private var _urlChanged:Boolean = false;

              protected var request:HTTPService;
              protected var timer:Timer;

              public function initialized(document:Object, id:String):void
              {
              initializeTimer();
              }

              public function get url():String{
              return _url;
              }
              public function set url(value:String):void{
              _url = value;
              _urlChanged = true;
              }

              public function get interval():int{
              return _interval;
              }
              public function set interval(value:int):void{
              _interval = value;
              initializeTimer();
              }

              protected function initializeTimer():void{
              if (timer)
              timer.stop();
              timer = new Timer(interval);
              timer.addEventListener(TimerEvent.TIMER, handleTimerTick);
              timer.start();
              }

              protected function handleTimerTick(event:Event):void{
              if (_urlChanged){
              _urlChanged = false;
              request = new HTTPService();
              request.url = url;
              request.method = "POST";
              request.resultFormat = HTTPService.RESULT_FORMAT_TEXT; //If you like you can add a property for this
              request.addEventListener(FaultEvent.FAULT, passOnEvent);
              request.addEventListener(ResultEvent.RESULT, passOnEvent);
              }
              if (request)
              request.send();
              }

              protected function passOnEvent(event:Event):void{
              dispatchEvent(event);
              }
              }
              }

              Now you can just put the following into your application:
              <lang:KeepAlive url=" http://www.google.com" result="myText.text = event.result as String;" fault="trace(event.fault.message)"/>

              You can change the interval if you like. You don't need to add listeners for the result or for the fault - but if you wanted to respond to an event you can.

              You'll need to have a servlet on your server that this posts to (we use POST so it doesn't cache the result - otherwise it'll only tell the server the first time).

              That should do the trick.
              Tim
              • 4. Re: Can I have a function performed on application close?
                phi2265 Level 1
                wow man, that looks great.. i'm not to the point of doing that yet... i have more to do than i thought i did. but i have saved that code and i will post when i get it all working! thanks a lot!

                • 5. Re: Can I have a function performed on application close?
                  phi2265 Level 1
                  alright, i've got the package in my application.. but when i use the command <lang:KeepAlive... i get an error, i've never seen <lang: before and i cant find anything about it in the documentation... what do i have to do to make this work?
                  • 6. Re: Can I have a function performed on application close?
                    FlightGuy Level 1
                    The lang: is just a result of the name of the package I've chosen (com.spears.lang). If you're using FlexBuilder, type

                    <KeepAlive

                    in your source code, and then (before the '>'), press Shift-Space, and it will automatically import your package and assign a prefix.

                    If you still have problems with that, shout and I'll walk you through doing it manually (I'm away until Friday, so it won't be 'till then - unless you reply today).

                    Tim
                    • 7. Re: Can I have a function performed on application close?
                      gdoumenc Level 1
                      FlightGuy,

                      Your code is interesting..

                      Adobe's guys why don't you define a list of interesting example code in this forum?... This will be very helpfull

                      Just my 3 cents
                      • 8. Can I have a function performed on application close?
                        phi2265 Level 1
                        Tim,

                        I'm not sure why I can't get this to work.. I've tried a number of things and I always get an error. Here's what I have..

                        file name is KeepAlive.as
                        inside is all of the code, just how you have it.

                        I can put it in the mxml, it works as <lang:KeepAlive.. the list of variables comes up when I push space, like any other component.. but when I save, I get an error on that line saying "Could not resolve <lang:KeepAlive> to a component implementation." I can't figure out what I dont have here, or what I'm doing wrong.


                        • 9. Re: Can I have a function performed on application close?
                          michael_ramirez44 Level 1
                          Let me see if I have the issue correct . You have a Flex application. When the user logs in you set a value in the database to true. When the user logs out you set the value to false. You want to set the value to false if the user closes the browser window. First question, why do you need to save the logged in status in database? Is there another application that uses this value?

                          Michael
                          • 10. Can I have a function performed on application close?
                            phi2265 Level 1
                            Yes there is, I have a whole backend management application that is part of this project. This is so updating is pretty much brainless. But I want to be able to collect information about the users.

                            Edit:
                            Yes you have the issue correct. I was also thinking about having an active user counter up in the corner or something.
                            PS The address in my signature is old.. I've since set up a server to host the site locally.
                            • 11. Re: Can I have a function performed on application close?
                              FlightGuy Level 1
                              Hi Jayson,

                              A couple of things to check: the first line of my sample code says "package com.spears.lang";

                              What is the package at the top of your KeepAlive.as? If it is the same as mine, then the file needs to be at com/spears/lang/KeepAlive.as, as this is where the compiler will look for it. If you've got it in the root with your application, remove the package line.

                              Tim
                              • 12. Can I have a function performed on application close?
                                phi2265 Level 1
                                Tim,

                                I have it running, I should have realized com.spears.lang was referring to directories. Now I'm trying to decide what it is I have to do on result and fault. Fault is where I would make a call for the user to be logged out right?

                                Thanks.

                                edit: I've come a long way recently.. heres a look: (link removed)

                                • 13. Re: Can I have a function performed on application close?
                                  FlightGuy Level 1
                                  Hi Jayson,

                                  I wouldn't expect you to need to do anything with Fault. This is the event that will be dispatched if the client sends a keepalive message to the server, but the message is for some reason undeliverable (eg. your server has been shut down). You may choose to do something on the client, or you may simply choose to ignore the fault and leave it to try again.

                                  The Result event is dispatched every time your keepalive request is replied to by your server. You may choose to send nothing back from your server (an empty response - the event will still be dispatched though), or you may choose to send any sort of status message back. As you suggested earlier, you may respond with a logged-on user count, or if the user is logged in and a message arrives for him, you may choose to push it out to the client.

                                  In the sample code I posted I had a resultType of text, you could use e4x, or any other format type. If you're going to respond with much data, I would suggest object or e4x. If you're just using this to tell the server that the client is still alive, you don't need to do anything with the response.

                                  On the server side you can identify the connection this post came from. You will probably be recording that the user is connected, and the last time a keepalive was received from the user's client. When you haven't heard from a specific session for some timeout period, you can assume that the client has been closed, or the communication channel has been lost somehow, and log the user off.

                                  What are you using for the server component of your architecture?

                                  Tim
                                  • 14. Re: Can I have a function performed on application close?
                                    phi2265 Level 1
                                    I'm using ASP. All it does right now is generate XML based on directory structure for photo galleries and such.
                                    I'm also using CF, well FDS is using it anyway.. I'm just starting to play around with CF so I dont understand it all yet.

                                    I understand what to do with the response from the KeepAlive now.. just gotta figure out how I'm gonna write it.

                                    Eventually I'm going to have a blog/message forum so pushing messages to the client based on the KeepAlive status is a good idea.

                                    I'm trying to think of how i would get that data from the post back into flex.. I guess I could have an xml file created by the script getting the post that is then fed back into flex. Does that sound right?
                                    • 15. Re: Can I have a function performed on application close?
                                      FlightGuy Level 1
                                      If I understand your question properly, then yes, it sounds right. Technically not an xml "file" - strictly speaking an xml document, streamed over http. If you're more comfortable with it, you can simply respond in text, but that's less flexible if you want to send different types of data.

                                      You don't even need to use the keepalive response as the means to deliver the content itself - you can use the response from the keepalive just to tell the client that there is new data, and the client can then turn around and request it. Whatever fits best.

                                      I don't use FDS, but I believe if you're using FDS you can actually push unsolicited data to the client, so it may be unnecessary to try to use the keepalive.

                                      TIm
                                      • 16. Re: Can I have a function performed on application close?
                                        ctzn99 Level 1
                                        Perhaps i'm missing something (and it's very likely) but wouldn't it be easier to simply have the browsers unload event fire a message off to the flex application?
                                        • 17. Re: Can I have a function performed on application close?
                                          phi2265 Level 1
                                          ctzn99,

                                          I don't believe that flex is capable of listening for that event, if it is.. that'd be great! Do you know if that is possible?

                                          Tim,

                                          Yes, FDS does push unsolicited data to the client.. it's actually pretty damn sweet if I do say so.

                                          I'm thining for this user logout function that I'll have a check performed every 5 mins or so to see if the client has responded, and if not then they're logged out. I'm gonna mess around with that right now and see what I can come up with.

                                          • 18. Re: Can I have a function performed on application close?
                                            ctzn99 Level 1
                                            You're right, I don't think flex can listen to that event but, the browser can and, in turn from javascript you send a message to an exposed action script method in the unload event handler.

                                            However, i'm not sure if it will actually work. I suspect what will happen is...

                                            1) User clicks close on browser.
                                            2) Unload event is fired and caught in javascript.
                                            3) Javascript code runs and sends message to action script.
                                            4) Javascript exits out of the method and browser closes.
                                            5) Action script can't do anything because it no longer exists because browser closed window before it had a chance?

                                            Just to satisfy my own curiosity I'm going to make a mock up. I'll post my results for ya.

                                            Zach
                                            • 19. Re: Can I have a function performed on application close?
                                              phi2265 Level 1
                                              Zach,

                                              You know what, I've seen that code and I can get it for you if have any trouble.. or you can search for it. I joined the flexcoders yahoo group, tons of code gets posted there. I have read about that, but I'm currently not using javascript at all and not even using an html wrapper, so I don't think I'm gonna use that.
                                              I almost have this working, what Tim and I have been talking about, as soon as I figure out what went wrong with my user database and why my edits to it aren't working all the time.
                                              I have the KeepAlive function posting the time as a result, and the timer updates every 5 seconds on a successful result. This will be posted to the user name, and then the management application I have will log someone out after 10 minutes or whatever I set it for.


                                              • 20. Re: Can I have a function performed on application close?
                                                ctzn99 Level 1
                                                Jayson,
                                                I did mockup a quick example of what I was talking about, it works in IE7 but was throwing an error in firefox, it's probably something that I could figure out given time but, I really just wanted to see if I could figure out and if it would work.

                                                So, while clearly if you test my sample in IE7 the unload event does get sent to the flash player BUT, as I surmised above because the browser is shutting down it's very possible that anything that had a time delay (like calling a web server or database) wouldn't make it through execution before the browser closed. In my demo app I added an alert to the shutdown just so I could see that there was in fact something happening in the flash player.

                                                I've included the demo here for anyone else following this thread:
                                                http://www.binarydemon.com/closttest.zip

                                                Clearly what you are working on with Tim is the better solution.

                                                Best of Luck,
                                                Zach

                                                • 21. Re: Can I have a function performed on application close?
                                                  FlightGuy Level 1
                                                  You will, in fact, see that the javascript was option (b) on the second post on this thread - I actually use that solution for something I'm doing and it works fine in IE - the specific example in which I use this the flex app is actually wrapped in an hta (Microsoft Hypertext Application), so I know it's only ever run from IE. I need this because I wanted to be able to prompt the user to save if he had unsaved edited data. In fact I see there is sample code for it in my first post on this thread.

                                                  The problem with this as a means to know who's on and who's off, is that it depends on an orderly close on the client. Frequently you don't get that - either because of a browser crash, a process being killed, or most often, the communications being lost. The keepalive option gives you a reliable sense as to whether the things actually still there.

                                                  Tim
                                                  • 22. Re: Can I have a function performed on application close?
                                                    phi2265 Level 1
                                                    Tim,

                                                    Thanks a lot for the code and the patients with explaining it to me.. I have it all working now. The KeepAlive posts a time/date to the user database, which is then handled via another mxml application I have for backend management. The users are logged out according to a timer, after no update (from the keepalive) for an interval of like 5 minutes. I ran it for a few hours, and it all works great. I'm a little out of it as I've been at the office for over 24 hours, I've learned so much in the past day! haha. Thanks again!


                                                    • 23. Re: Can I have a function performed on application close?
                                                      JohnLeger Level 1
                                                      You can do it by using a LocalObject as in the example I've provided below.

                                                      <?xml version="1.0" encoding="utf-8"?>
                                                      <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="vertical">

                                                      <mx:Script>
                                                      <![CDATA[
                                                      import mx.controls.Alert;
                                                      [Bindable]
                                                      public var myName:String;

                                                      public function getName():String
                                                      {
                                                      var object:SharedObject = SharedObject.getLocal("userinfo");
                                                      return object.data.myName;
                                                      }

                                                      public function setName(myName:String):void
                                                      {
                                                      var object:SharedObject = SharedObject.getLocal("userinfo");
                                                      object.data.myName = myName;
                                                      Alert.show("Your data was saved locally", "Confirmation");
                                                      }

                                                      ]]>
                                                      </mx:Script>

                                                      <mx:Panel title="Enter Data">
                                                      <mx:Form>
                                                      <mx:FormItem label="Your Name:">
                                                      <mx:TextInput id="nameInput"/>
                                                      </mx:FormItem>
                                                      <mx:FormItem>
                                                      <mx:Button label="Save" click="setName(nameInput.text)"/>
                                                      </mx:FormItem>
                                                      <mx:FormItem>
                                                      <mx:Button label="Get" click="myName=getName()"/>
                                                      <mx:Label text="{myName}" fontSize="14"/>
                                                      </mx:FormItem>
                                                      </mx:Form>
                                                      </mx:Panel>

                                                      </mx:Application>


                                                      I just implemented full role authentication using a combination of ColdFusion MX 7.02, Flex 2, ActionScript and SQL Server Epress 2005. Part of my authentication process gives the logged in user the choice of being remembered. If the check box is checked he can be automatically logged in whenever the application restarts.

                                                      I have chosen to give my users the option of being fully remembered (ie. username, password and role) OR partially remembered (ie. just their username). The wisdom to use one or the other then rests with the user who may be the only one who has access to his/her computer.

                                                      This example shows an Alert to show that the information has been saved locally. The logic in this example helped me out immensely.

                                                      Happy coding!!! :)

                                                      John
                                                      • 24. Re: Can I have a function performed on application close?
                                                        phi2265 Level 1
                                                        That's really a good idea. I just used a shared object for the first time to transfer a value to another mxml component within my application. When I was first reading about it it said how it creates a file on the local computer, or gets it if its already there.

                                                        I think I'm going to use that, that's a good example.