Issues with ArcGISTiledMapServiceLayer in IE8 and IE7

1869
13
03-20-2013 01:10 PM
AaronConnolly
Regular Contributor
Hi,

At version 3.3 there could be an issue with the ArcGISTiledMapServiceLayer. When my app loads I set show/hide one of 4 layers that represents my base map layer. Throughout the use of the app the user can switch between those different layers (think: "streets", "hybrid", "topo", etc...). When they choose any of those options I toggle between the layer's visbility.

This works without fail in all browsers that we've tested, except for IE8 and IE7. Occasionally I will find that one of my ArcGISTiledMapServiceLayer objects is NULL when I try to hide/show it.

When the page loads it hides/shows those layers based on some setting for "streets", etc..."

This lead me back to the docs for the layer object and I wondered if my layers were not loaded properly because I didn't see any errors from the "onError" call back I had hooked up.

As a general question, why would my layer object be NULL (in IE8 and IE7) if my code between versions 2.8 and 3.3 never changed? Remember when the page loads up I wait to add the layers to the map until the map is ready, etc...

Another question is, what's with the documentation on ArcGISTiledMapServiceLayer? It seems to contradict itself with the code sample:

onLoad(layer) reads:

"Fires after layer properties for the layer are successfully populated. This event must be successful before the layer can be added to the map."

Then under code snippets:

"In Internet Explorer, due to resource caching, the onLoad event is fired as soon as the layer is constructed. Consequently you should check whether the layer's loaded property is true before registering a listener for the onLoad event:"

The code reads:

function init() {
  //setting initial extent in constructor
  var map = new esri.Map("mapDiv", { extent: new esri.geometry.Extent(...) });

  //or use set extent method
  var map = new esri.Map("mapDiv");
  map.setExtent(new esri.geometry.Extent(...));

  //add first layer
  map.addLayer(...);
}


This code doesn't check for "loaded == true" and neither does it hook up the onLoad event. What gives? Can we get a legit sample for how to hook up one of these layers with an onError and onLoad event? The samples for using a "basemap" now tell you to use the new "basemap" property of the map object. I don't want to do that because I want to control which layers are used for "streets", "hybrid", etc...

Can someone post a little code that shows how to properly create, hook events to and add an ArcGISTiledMapServiceLayer to a map and also explain whether or not it's wise to use the hide/show property of that layer object to control its visibility.

Frustrated ...

Thanks,
- Aaron
0 Kudos
13 Replies
AaronConnolly
Regular Contributor
Continued from previous post ...

To reproduce this yourself you need to create a page called index.htm. It needs to be in the same directory of the website that holds the page with the map and script. Here's the index.htm, that I am using:

index.htm:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Debugging</title>
    <style type="text/css">
        
        body { font-size: 100%; font-family: Verdana; margin: 20px; }
        
    </style>
</head>
<body>
<ul>
    <h3>Test Pages</h3>
    <li><a href="test-layers-ie8-ie7.html">Test Layers in IE8 and IE7</a></li>
</ul>
</body>
</html>


Now the script page whose code has been provided before, has been slightly updated:

1. The streets won't be shown until all the layers have loaded.
2. The hard coded LODs have been removed.

This functions normally in Firefox, and IE 9 and Chrome, but Chrome throws a bunch of odd javascript warnings.

test-layers-ie8-ie7.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test Map Layers in IE8 and IE7</title>
    
    <!-- ESRI Required -->
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.3/js/esri/css/esri.css" />
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.3/js/dojo/dijit/themes/tundra/tundra.css"/>
    <script type="text/javascript">var dojoConfig = { parseOnLoad: true };</script>
    <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/3.3"></script>
    
    <script type="text/javascript">

        dojo.require("esri.map");

        var map;
        var streetsUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer";
        var topoUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer";
        var transportUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer";
        var satelliteUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
       
        var LAYER_STREETS = null;
        var LAYER_TOPO = null;
        var LAYER_TRANSPORT = null;
        var LAYER_SATELLITE = null;

        function init() {

            var initExtent = new esri.geometry.Extent({ "xmin": -13056017.708638752, "ymin": 4028145.398141955, "xmax": -13030946.363361249, "ymax": 4042916.8538580453, "spatialReference": { "wkid": 102100 } });
            
            map = new esri.Map("map");

            LAYER_STREETS = createLayerWithUrl(streetsUrl);
            LAYER_TOPO = createLayerWithUrl(topoUrl);
            LAYER_SATELLITE = createLayerWithUrl(satelliteUrl);
            LAYER_TRANSPORT = createLayerWithUrl(transportUrl);

            toggleStreets();
        };

        function createLayerWithUrl(url) {

            var layer = new esri.layers.ArcGISTiledMapServiceLayer(url)

            if (layer != undefined && layer != null) {

                logMessage("CREATED: ArcGISTiledMapServiceLayer, listening for error, loaded events.");

                dojo.connect(layer, "onError", tiledMapServiceLayerError);
                dojo.connect(layer, "onLoad", tiledMapServiceLayerLoaded);
            }
            else {

                logMessage("CREATED: failed. layer is null after constructor.");
            }

            return layer;
        }

        function tiledMapServiceLayerLoaded(layer) { 

            map.addLayer(layer);
            layer.hide();

            logMessage("LOADED: Layer loaded and added to map: '" + layer.id + "'");

            checkLayersLoaded();
        }

        function tiledMapServiceLayerError(error) {

            var message = "";

            if (error.message != undefined && error.message != null) {

                message += error.message;
            }

            logMessage("ERROR: A problem occurred retrieving the layer. Error Message: '" + message + "'");
        }

        function checkLayersLoaded() {

            if (LAYER_STREETS.loaded == true &&
                LAYER_TOPO.loaded == true &&
                LAYER_TRANSPORT.loaded == true &&
                LAYER_SATELLITE.loaded == true) {

                logMessage("CHECK: all layers loaded!");

                logMessage("setting map cache to = 'world-street'");
                toggleStreets();
            }
            else {

                logMessage("CHECK: not ready");
            }
        }

        function logMessage(message) {

            // Check for a console object
            var console = window['console'];

            // Log a message if a log property is available
            //---------------------------------------------
            if (console && console.log) {

                console.log(message);
            }
        }

        function toggleStreets() {

            if (LAYER_STREETS.loaded == true) {

                LAYER_STREETS.show();
                LAYER_TOPO.hide();
                LAYER_TRANSPORT.hide();
                LAYER_SATELLITE.hide();
            }
            else {

                logMessage("SHOW 'streets' failed. LAYER_STREETS not loaded.");
            }
        }

        function toggleTopo() {

            if (LAYER_TOPO.loaded == true) {

                LAYER_STREETS.hide();
                LAYER_TOPO.show();
                LAYER_TRANSPORT.hide();
                LAYER_SATELLITE.hide();
            }
            else {

                logMessage("SHOW 'topo' failed. LAYER_TOPO not loaded.");
            }
        }

        function toggleHybrid() {

            if (LAYER_TRANSPORT.loaded == true && LAYER_SATELLITE.loaded == true) {

                LAYER_STREETS.hide();
                LAYER_TOPO.hide();
                LAYER_TRANSPORT.show();
                LAYER_SATELLITE.show();
            }
            else {

                logMessage("SHOW 'hybrid' failed. LAYER_TRANSPORT, LAYER_SATELLITE not loaded.");
            }
        }

        dojo.addOnLoad(init);

    </script>
    <style type="text/css">
        body { font-size: 100%; font-family: Verdana; }
        #map { height: 600px; width: 800px; margin: 50px auto; border: 3px solid black; }
    </style>
</head>
<body>
<p><a href="index.htm">index</a></p>
<div class="search">
    <input type="button" value="Streets" onclick="toggleStreets();" />
    <input type="button" value="Topo" onclick="toggleTopo();" />
    <input type="button" value="Hybrid" onclick="toggleHybrid();" />
</div>
<div id="map">
</div>
</body>
</html>


Please let me know if you can reproduce this on your side. Thanks.
0 Kudos
AaronConnolly
Regular Contributor
Has anyone else been able to re-create this issue with the sample code and project I provided? I'd really like to know what is going on with IE 8 and 7 when the browser loads the page but fails to throw any errors or load the tiled layers. I've escalated this to ESRI support but I haven't received any feedback yet.
0 Kudos
KellyHutchins
Esri Frequent Contributor
Aaron,

How about letting the basemap widget handle everything - here's an example that adds the layers you want to the  widget and creates a button for each basemap. Clicking the button will display the associated basemap.




<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9">
    <!--The viewport meta tag is used to improve the presentation and behavior of the samples 
      on iOS devices-->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>Display Multiple ArcGIS Online Services</title>
    <link rel="stylesheet" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.4/js/dojo/dijit/themes/claro/claro.css">
    <link rel="stylesheet" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.4/js/esri/css/esri.css">

    <style>
      html,body,#map{
        padding:0;
        margin:0;
        height:100%;
        width:100%;
      }

    </style>
    <script>var dojoConfig = { parseOnLoad: true };</script>
    <script src="http://serverapi.arcgisonline.com/jsapi/arcgis/3.4/"></script>
    <script>
      dojo.require("esri.map");
      dojo.require("dijit.form.Button");
      dojo.require("esri.dijit.BasemapGallery");
      dojo.require("dijit.form.Button");
      dojo.require("dijit.Menu");
      
      var map;
      var basemapGallery;

      function init() {
        map = new esri.Map("map", {
          center: [-31.036, 42.747],
          zoom: 3
        });
        //define the layers that will be used for each basemap 
        var streetLayer = new esri.dijit.BasemapLayer({
          url: "http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"
        });
        var topoLayer = new esri.dijit.BasemapLayer({
          url: "http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"
        });
        var transportLayer = new esri.dijit.BasemapLayer({  //hybrid
          url: "http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer"
        });
        var satelliteLayer = new esri.dijit.BasemapLayer({ //hybrid
          url: "http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
        });
        //Create the basemaps 
        var streets = new esri.dijit.Basemap({
          layers: [streetLayer],
          title: "Streets"
        });
        var topo = new esri.dijit.Basemap({
          layers: [topoLayer],
          title: "Topo"
        });
        var hybrid = new esri.dijit.Basemap({
          layers: [transportLayer, satelliteLayer],
          title: "Hybrid"
        });

        var basemaps = [streets,topo,hybrid];

        //build the basemap gallery 
        basemapGallery = new esri.dijit.BasemapGallery({
          showArcGISBasemaps: false,
          basemaps: basemaps,
          map: map
        });
        //add a basemap button for each of the above maps 
         dojo.forEach(basemapGallery.basemaps, function(basemap) {      
          dojo.create("input", {
            type: "button",
            value: basemap.title,
            onclick: dojo.hitch(this, function(){
                this.basemapGallery.select(basemap.id);
            })
          },"basemaps_bar");
        });
      }
    dojo.ready(init);
    </script>
  </head>
  <body class="claro">
      
      <div id="map">
        <div id="basemaps_bar" style="position:absolute; right:50px; top:10px; z-Index:99;">
        </div>
      </div>

  </body>
</html>

0 Kudos
AaronConnolly
Regular Contributor
Kelly,

This looks like it would work, however it doesn't explain why we're having this issue in the first place. Can you explain why the layers don't load or throw errors when you hop between an index page and the map page? Upgrading to version 3.3 broke this particular portion of our application where users arrive at our home page and click through to our map page. We didn't have these problems with versions < 3.3.

Any thoughts?
0 Kudos