Select to view content in your preferred language

Save session state

4044
19
04-08-2010 11:23 AM
DouglasGuess
Regular Contributor
I'm looking to modify the SFV to handle saving a users session state.  More specifically, I would like to be able to save what layers in the LiveMapsWidget are on, extent the map is at, etc....  So, when that user leaves the map, maybe a prompt asking if they would like to "save their settings".  Then, when they return, another prompt asking if they would like to "restore their settings" and everything is as it was, visible layers, extent, etc... something like that.

Has anyone implemented something like this?  Casey Bentz sent me some sample code (thanks Casey!) but it's not using the SFV and I'm having some difficulty getting this to work.  I believe this can be accomplished using SharedObjects but not exactly sure how to get it to work with the SFV.

I read at http://forums.esri.com/Thread.asp?c=158&f=2421&t=284721&mc=27#msgid883724 that Robert Scheitlin has an implementation for this. Robert, any help would be great!

Thanks.
Tags (2)
0 Kudos
19 Replies
RobertScheitlin__GISP
MVP Emeritus
Daniel,

  I tested this again and low and behold it was not working, so I dug in and guess there is some syntax errors in the JavaScript portion so try replacing your index.template.html with this:

<!-- saved from url=(0014)about:internet -->
<html lang="en">

<!-- 
Smart developers always View Source. 

This application was built using Adobe Flex, an open source framework
for building rich Internet applications that get delivered via the
Flash Player or to desktops via Adobe AIR. 

Learn more about Flex at http://flex.org 
// -->

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>${title}</title>
<script src="AC_OETags.js" language="javascript"></script>
<style>
body { margin: 0px; overflow:hidden }
</style>
</head>

<body scroll='no'>
<script language="JavaScript" type="text/javascript">
<!--
  AC_FL_RunContent(
     "src", "${swf}",
     "width", "${width}",
     "height", "${height}",
     "align", "middle",
     "id", "${application}",
     "quality", "high",
     "bgcolor", "${bgcolor}",
     "name", "${application}",
     "allowScriptAccess","sameDomain",
     "type", "application/x-shockwave-flash",
     "pluginspage", "http://www.adobe.com/go/getflashplayer"
 );
// -->
</script>
<script language="JavaScript" type="text/javascript">
 window.onbeforeunload = clean_up;

 function clean_up()
 {
  var flex = document.${application} || window.${application};
  flex.savesettings();
 }
</script>
<noscript>
 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
   id="${application}" width="${width}" height="${height}"
   codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
   <param name="movie" value="${swf}.swf" />
   <param name="quality" value="high" />
   <param name="bgcolor" value="${bgcolor}" />
   <param name="allowScriptAccess" value="sameDomain" />
   <embed src="${swf}.swf" quality="high" bgcolor="${bgcolor}"
    width="${width}" height="${height}" name="${application}" align="middle"
    play="true"
    loop="false"
    quality="high"
    allowScriptAccess="sameDomain"
    type="application/x-shockwave-flash"
    pluginspage="http://www.adobe.com/go/getflashplayer">
   </embed>
 </object>
</noscript>
</body>
</html>
0 Kudos
DanielLewis
Emerging Contributor
Daniel,

  I tested this again and low and behold it was not working, so I dug in and guess there is some syntax errors in the JavaScript portion so try replacing your index.template.html with this:

<!-- saved from url=(0014)about:internet -->
<html lang="en">

<!-- 
Smart developers always View Source. 

This application was built using Adobe Flex, an open source framework
for building rich Internet applications that get delivered via the
Flash Player or to desktops via Adobe AIR. 

Learn more about Flex at http://flex.org 
// -->

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>${title}</title>
<script src="AC_OETags.js" language="javascript"></script>
<style>
body { margin: 0px; overflow:hidden }
</style>
</head>

<body scroll='no'>
<script language="JavaScript" type="text/javascript">
<!--
  AC_FL_RunContent(
     "src", "${swf}",
     "width", "${width}",
     "height", "${height}",
     "align", "middle",
     "id", "${application}",
     "quality", "high",
     "bgcolor", "${bgcolor}",
     "name", "${application}",
     "allowScriptAccess","sameDomain",
     "type", "application/x-shockwave-flash",
     "pluginspage", "http://www.adobe.com/go/getflashplayer"
 );
// -->
</script>
<script language="JavaScript" type="text/javascript">
 window.onbeforeunload = clean_up;

 function clean_up()
 {
  var flex = document.${application} || window.${application};
  flex.savesettings();
 }
</script>
<noscript>
 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
   id="${application}" width="${width}" height="${height}"
   codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
   <param name="movie" value="${swf}.swf" />
   <param name="quality" value="high" />
   <param name="bgcolor" value="${bgcolor}" />
   <param name="allowScriptAccess" value="sameDomain" />
   <embed src="${swf}.swf" quality="high" bgcolor="${bgcolor}"
    width="${width}" height="${height}" name="${application}" align="middle"
    play="true"
    loop="false"
    quality="high"
    allowScriptAccess="sameDomain"
    type="application/x-shockwave-flash"
    pluginspage="http://www.adobe.com/go/getflashplayer">
   </embed>
 </object>
</noscript>
</body>
</html>


Robert,

Thanks, that worked.  Are the variables in the index.html (i.e. ${application}) supposed to be picked up from another file?  I have to go through and change them to the application title, file name, etc.

Now I'm going to try to add a popup to ask the user if they want to restore the state or take the default.
0 Kudos
RobertScheitlin__GISP
MVP Emeritus
Daniel,

   Try this code for that, maybe I got it all here:

//This is code for MapManager.mxml

   //config
      private function config(event:AppEvent):void
      {      
       configData = event.data as ConfigData;

       map = new Map();
       map.id = "map";
       map.zoomSliderVisible = false;
       map.addEventListener(MapEvent.LOAD, mapLoadComplete);
       this.addChild(map);
          SiteContainer.dispatchEvent(new AppEvent(AppEvent.MAP_LOADED, false, false, map));
          
          var infoContainer:Canvas = new Canvas();
          infoContainer.percentWidth = 100;
          infoContainer.percentHeight = 100;
          infoContainer.horizontalScrollPolicy = "off";
          infoContainer.verticalScrollPolicy = "off";
          this.addChild(infoContainer);
          infoPopup = new InfoPopup();
          infoPopup.map = map;
          infoContainer.addChild(infoPopup);
         
          navToolbar = new Navigation();
          navToolbar.map = map;
          
          drawToolbar = new Draw();
          drawToolbar.map = map;
          drawToolbar.addEventListener(DrawEvent.DRAW_END, onDrawEnd);
          
          getDefaultStatus();
          
          var i:int = 0;
         
          for (i = 0; i < configData.configExtents.length; i++)
          {
           var id:String = configData.configExtents.id;
           var ext:String = configData.configExtents.extent;
           var extArray:Array = ext.split(" ");
           var extent:Extent = new Extent(Number(extArray[0]), Number(extArray[1]), Number(extArray[2]), Number(extArray[3]));
           if (id == "full")
           {
            fullExtent = extent;
           }
           if (id == "initial")
           {
            map.extent = extent;
           }
          }
       
    for (i = 0; i < configData.configMap.length; i++)
          {
           var label:String  = configData.configMap.label;
           var type:String = configData.configMap.type;
           var url:String =  configData.configMap.url;
           var visible:Boolean = configData.configMap.visible;
           var alpha:Number = Number(configData.configMap.alpha);
           var style:String = configData.configMap.style;
           
           switch (type.toLowerCase())
     {
      case "tiled":
      {
       var tiledlayer:ArcGISTiledMapServiceLayer = new ArcGISTiledMapServiceLayer(url);
       tiledlayer.id = label;
       tiledlayer.name = label;
       tiledlayer.visible = visible;
       tiledlayer.alpha = alpha;
       map.addLayer(tiledlayer);
       break;
      }
       
      case "dynamic":
      {
       var dynlayer:ArcGISDynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer(url);
       dynlayer.id = label;
       dynlayer.name = label;
       dynlayer.proxyURL = configData.proxy;
       dynlayer.visible = visible; 
       dynlayer.alpha = alpha;
       map.addLayer(dynlayer);
       break;
      }
      case "virtualearth":
      {
       var veTiledLayer:VETiledLayer =  new VETiledLayer();
       veTiledLayer.id = label;
        veTiledLayer.tokenURL = url;
        veTiledLayer.environment = "production";
        veTiledLayer.visible = visible; 
        veTiledLayer.alpha = alpha;
        veTiledLayer.mapStyle = style;
        veTiledLayer.name = label;
        map.addLayer(veTiledLayer);
        break;
      } 
     }
     
          }
      
          map.panArrowsVisible = false;
       map.zoomSliderVisible = true;
       map.logoVisible = true;
    
    Alert.show("Do you want to load your last session state? This will restore the maps extent " +
       "and the visiblity of the layers that were set in your last session." +
       "Do you want to load your previous session settings?", "Question", Alert.YES|Alert.NO, null, 
       alertClickHandler, expClass, Alert.YES);
      }
      
      private function alertClickHandler(event:CloseEvent):void
   {
    if (event.detail==Alert.YES)
    {
     //This is where we are loading the state from the saved object       
        settingsSO = SharedObject.getLocal("MYSFV13SAVEDSETTINGS");
        if (settingsSO.size > 0) {
         callLater(setExt,[settingsSO.data.extent]);
         function setExt(obj:Object):void
         {
          var mext:Extent = new Extent(obj.xmin, obj.ymin, obj.xmax,obj.ymax,map.spatialReference);
          map.extent = mext;
         }
         var acVisLayers:ArrayCollection = settingsSO.data.vislayers as ArrayCollection;
         
         MapUtil.forEachMapLayer(map, function(layer:Layer):void {
          var cLayId:int = 0;
          for(var i:Number=0; i<acVisLayers.length -1;i++)
          {
           if(acVisLayers.name == layer.name)
           {
            cLayId = i;
            break;
           }
          }
          
                var layVisAc:ArrayCollection;
                if (layer is ArcGISDynamicMapServiceLayer) {
                 layer.visible = acVisLayers[cLayId].visible;
        ArcGISDynamicMapServiceLayer(layer).visibleLayers = acVisLayers[cLayId].visarray;
       } else if (layer is ArcIMSMapServiceLayer) {
        layer.visible = acVisLayers[cLayId].visible;
        ArcIMSMapServiceLayer(layer).visibleLayers = acVisLayers[cLayId].visarray;
       } else if (layer is ArcGISTiledMapServiceLayer) {
        layer.visible = acVisLayers[cLayId].visible;
       }
      });
     }
       }
0 Kudos
JamesKo
Occasional Contributor
Robert,

This has been a cool addition to my website but I did notice something unusual with group layers. The checkbox for the group layer is not checked even though I had selected it in the previous session; however, the visible layers under the group layer are visible on the map.
0 Kudos
RobertScheitlin__GISP
MVP Emeritus
James,

   This has always been an issue with the toc component, it does not update to programmatic changes to a layers visibility...
0 Kudos
AshleyOwens
Emerging Contributor
Hi Robert!  Is this code available in the Code Gallery for ArcGIS API for Flex?  What Flex & ArcGIS Server versions are compatible with the code?

Thanks for all your great work!
Ashley
0 Kudos
RobertScheitlin__GISP
MVP Emeritus
Ashley,

   No this is just a code sample to get developers started. It is nearly two years old and I don't even remember what version I developed this for.
0 Kudos
AshleyOwens
Emerging Contributor
I am able to save widget information (state, width, height, x/y position), but am having trouble setting these values on the widgets when the app loads the next time.  There is one exception: if the widget is set to preload in the config XML, it is loaded into the WidgetManager and I can retrieve it and set the values -
var wgt:IBaseWidget = ViewerContainer.getInstance().widgetManager.getWidget(Number(acWidgets.id),false);
wgt.setState(wgtObj.state);
if(wgt.getState() != WidgetStates.WIDGET_MINIMIZED)
{
 wgt.initialWidth = wgtObj.width;
 wgt.initialHeight = wgtObj.height;
}
wgt.setXYPosition(Number(acWidgets.x),Number(acWidgets.y));
wgt.setPreload(wgt.getState());
How can other widgets be accessed into an IBaseWidget object? I have tried several things such as retrieving from ModuleInfo -
wgt = moduleInfo.factory.create() as IBaseWidget;
I haven't found anything that works. Thanks for any insight!
0 Kudos
JessicaCondron
Emerging Contributor
Ashley I am trying to do the same thing with the widgets but haven't made it as far as you. How did you access the widget width, height, and x/y position? Thanks!
0 Kudos
AnthonyGiles
Honored Contributor
Jessica,

I am using a shared object in each widget to retain its state, to access the properties of the widget, I have used the following:

this.x --- x position of wid
this.y --- y position of widget
this.wTemplate.width --- width of widget
this.wTemplate.height --- height of widget

Hope this helps

Regards

Anthony
0 Kudos