5 Replies Latest reply on Apr 9, 2008 3:36 AM by cxf02

    preserve state in different tabs of the browser

    paulhergh
      Hi
      I have a simple application that has a login page with a login HttpService attached that returns yes or no, as the login was succesefull or not. If the login was successfull, I change the current state in "Logged In"
      The code for the login HttpService looks like this:

      <mx:HTTPService id="login_user" result="checkLogin(event)" showBusyCursor="true" method="POST" url="login.php" useProxy="false">
      <mx:request xmlns="">
      <username>
      {username.text}
      </username>
      <password>
      {password.text}
      </password>
      </mx:request>
      </mx:HTTPService>

      and it's working.

      the "states part":
      <mx:states>
      <mx:State name="Logged In">
      <mx:SetProperty target="{panel1}" name="width" value="100%"/>
      <mx:SetProperty target="{panel1}" name="height" value="100%"/>
      <mx:RemoveChild target="{password}"/>
      <mx:RemoveChild target="{username}"/>
      <mx:RemoveChild target="{label1}"/>
      <mx:RemoveChild target="{Submit}"/>
      <mx:RemoveChild target="{label2}"/>
      <mx:RemoveChild target="{image}"/>
      <mx:AddChild relativeTo="{panel1}" position="lastChild">
      <mx:MenuBar id="myMenuBar" change="menuHandler(event)" click="clickMenuHandler()" itemClick="mesaj(event)" showRoot="false" labelField="@label" dataProvider="{menuSrv.lastResult as XML}"/>
      </mx:AddChild>
      <mx:AddChild relativeTo="{panel1}" position="lastChild">
      <mx:Button x="1150" y="0" label="Logout" click="logout()"/>
      </mx:AddChild>
      <mx:AddChild relativeTo="{panel1}" position="lastChild">
      <mx:Image id="imageWelcome" source="logo.jpg" horizontalCenter="0" verticalCenter="-2" />
      </mx:AddChild>
      </mx:State>
      </mx:states>

      What I basically want to do is to preserve this login state, even if I'll open my application in a different tab. Tried so many different ways, FlexSessions, DRMAuthenticate, but none seems to work.

      Please tell me what's the "right way" of doing this, as I ran out of sollutions.
      Tnx,
      Paul
        • 1. Re: preserve state in different tabs of the browser
          slaingod Level 1
          Generally, the way I do it is on the server.

          1) User sees a login screen in Flex, puts in username and password.
          2) Pass that to server, server validates and responds
          3) Server stores this state in its database (or encrypted cookies, or on a file system, etc) and uses a session key or similar object to keep track of it in a cookie.
          4) Every request flex makes from thereon out will pass the cookie, so you can vaildate for each request.
          5) IN your browser, always call the server to see if you are logged in when you start up.

          EXCEPTION: IN FireFox and other browsers, when you upload a file, a different browser instance/session/cookie is used, so you will need to coordinate in the client and server to assign an upload to an authenticated user. I generally do this by returning a 'token', a database id and an md5 hash of the database id, which when the upload completes is received by the client and transmitted back to the server in a normal request so it can assign the upload to the proper user.

          Optionally, you could pass this info in the flashvars.

          • 2. Re: preserve state in different tabs of the browser
            paulhergh Level 1
            Thanks for your response.
            I'll try to do this server side "state preservation", but still I'd like to know if there is a way for flex to do this.
            • 3. Re: preserve state in different tabs of the browser
              slaingod Level 1
              You could communicate between multiple instances of your app with LocalConnection... If the connection already existed, you could ask the 'Master'. You might need to increment your connection name until you found a 'free slot' on the Master (and it would have to listen to slaves +1 connection). (This is about the only scenario where I could imagine LocalConnection would actually be useful in a tabbed browser.)

              It might also be possible with ExternalInterface and javascript, but I haven't used that in a while, so can't remember for sure if you can do cross-tab javascript comm. Maybe only if the Flex window is the one that opened it.
              • 4. Re: preserve state in different tabs of the browser
                paulhergh Level 1
                I'm trying with 2 swf files, one with the login and one with the main part of the application, and somehow decide from another php file witch one to be displayed, depending on the Session atributes.
                Hope to succeed!

                Tnx for your answer!
                • 5. Re: preserve state in different tabs of the browser
                  cxf02 Level 1
                  Try a Singleton approach to save "Global" information for application use.

                  Adapt this Singleton for use in your application if you like.
                  package net.procontent.persistance
                  {

                  // Singleton pattern for static datasource that can be accessed from the entire application

                  public class DataSource {

                  import mx.rpc.http.HTTPService;
                  import mx.collections.XMLListCollection;
                  import mx.rpc.events.FaultEvent;
                  import mx.rpc.events.ResultEvent;
                  import mx.controls.Alert;
                  import mx.events.*;
                  import flash.events.Event;

                  /**
                  * Private static variable for singleton handle
                  */
                  private static var dataSource:DataSource;

                  //just a test string for verifying stuff
                  private var testString:String = "This is the test string";

                  /**
                  * The content container for the XML File
                  */
                  private var xmlContent:XMLListCollection = new XMLListCollection();

                  /**
                  * The content service member
                  */
                  private var contentService:HTTPService;

                  /**
                  * The money method for returning the either instantiating a new instance or returning
                  * the handle to the static singleton
                  * @return the dataSource handle
                  *
                  */
                  public static function getInstance():DataSource {
                  if ( dataSource == null ) {
                  dataSource = new DataSource( );
                  }
                  return dataSource;
                  }

                  /**
                  * Public constructor because AS 3.0 will not accept it as private
                  * It either throws an error or populates the instance with data from
                  * the service
                  *
                  */
                  public function DataSource() {
                  // Check for if someone is trying to instantiate this more than once in the code
                  if (DataSource.dataSource != null) {
                  throw new Error( "Sorry, correct your code, one Singleton instance should be instantiated and you are trying to light off a second!" );
                  } else {
                  this.getData();
                  }
                  }

                  /**
                  * The method that sets the content service member with service information
                  * and populates the service wit the e4x XML file
                  *
                  */
                  public function getData():void {
                  contentService = new HTTPService() ;
                  contentService.url = "xml/contents.xml";
                  contentService.resultFormat = 'e4x';
                  contentService.destination = "DefaultHTTP";
                  contentService.useProxy = false;
                  contentService.addEventListener("result", setXmlContent);
                  contentService.addEventListener("fault", httpFault);
                  contentService.method = "post";
                  contentService.send();
                  }

                  /**
                  * Fault method called if there is a problem with the service connection. Caution, the HTTP service
                  * does not have very robust information concerning faults. This event is registered in the getData
                  * method and will fire as a result of issues with that service.
                  * @param event is the error event
                  *
                  */
                  private function httpFault(event:FaultEvent):void {
                  var faultstring:String = event.fault.faultString;
                  Alert.show(faultstring);
                  }

                  /**
                  * This event is registered in the getData method and sets the source of the xmlContent member
                  * with e4x XML data
                  * @param event
                  *
                  */
                  private function setXmlContent (event:ResultEvent):void {
                  this.xmlContent.source = event.result.content;
                  }

                  /**
                  * This method is the public means to use this singleton for retrieving an XML List to be used
                  * by TextAreas for content. Use of TextAreas for content is desired because of the scroll
                  * bar that TA's possess.
                  * @param key uses xpath features to seek an attribute the value of the attribute "id" as shown below:
                  * -------------------------- Example e4x object ----------------------------------------
                  * <contents>
                  * <content menuGroup="myMenuGroup" id="Home" menuLabel="My List Item Text" video="" image="" >
                  * <![CDATA[<font color="#CCCCCC" face="Arial, Helvetica, sans-serif" size="14">
                  * <font size="30">P</font>rofessional <font size="30">C</font>ontent offers <b>
                  * <i>Affordable Rich Internet Application Development...</i></font> ]]>
                  * </content>
                  * ----------------------------------------------------------------------------------------- ---------
                  * Calling this method as getXMLContent('Home') on an instatiated DataSource object will return an
                  * XMLList object that populates your TextArea with HTML
                  * @return the XMLList object with content as the payload
                  *
                  */
                  public function getXmlContent(key:String):XMLList {
                  return this.xmlContent.source.(@id == key) ;
                  }

                  /**
                  * This method will return an XMLListCollection that your List object will like and accept as items that are
                  * selectable. It uses the same format as the XML commented above
                  * @param key uses the menuGroup attribute in the above XML example to build a list of all XML
                  * elements that match that xpath criteria. You need to set the List attribute labelField="@menuLabel" to use the text
                  * for the list item.
                  * These two methods can be adjusted to use any attributes and any type of XML organization to populate
                  * lists and content selected from lists
                  * @return the XMLlistCollection for List item population
                  *
                  */
                  public function getXmlMenu(key:String):XMLListCollection {
                  var menu:XMLListCollection = new XMLListCollection();
                  menu.source = new XMLList(this.contentService.lastResult.content.(@menuGroup == key));
                  return menu;
                  }

                  /**
                  * Provided to return the service with all the content if there are other objects that require the
                  * data for more complex operations
                  * @return an HTTPService object populated with XML data
                  *
                  */
                  public function getContentService():HTTPService {
                  return this.contentService;
                  }

                  /**
                  * test method
                  * @return a String object
                  *
                  */
                  public function getTestString():String {
                  return this.testString;
                  }
                  }
                  }