[JS API 4.8+] MapView not fetching data when the "map" property value is replaced

1007
6
11-15-2018 06:32 AM
SebastianKvist
New Contributor II

Hi,

I provided two example use cases of how to update the property "map" of a MapView instance. These both worked pre-v4.8.

These use cases involves a map with a single MapImageLayer. It seems to be working better with default basemap-layers, although not custom created ones (new Basemap(...))..

Also, updating the extent or using goTo() doesn't trigger map data fetching.

Since I need to be able to utilize the possibility of changing the map property of a MapView, I would appreciate it if someone has any suggestions of workarounds?

I imagine that this bug is already discovered and reported, otherwise I hope this question is sufficient to confirm that it is a bug. Maybe it is fixed within the same fix as https://community.esri.com/thread/223936-js-api-49-ie11-updating-the-map-property-on-a-mapview-doesn... , but I just wanted to be sure to cover these use cases as well.

Thanks in advance,

Sebastian

0 Kudos
6 Replies
ArneDahlman
New Contributor III

Yes it seems that, if I don't use an ESRI-basemap, my map won't redraw automatically.
I first need to zoom or pan to trigger a redraw of map.
So when my application starts it just show a white surface instead of my map.

Any workarounds for this issue?
API 4.9, IE & Chrome

To reproduce problem: use the sample "Intro to MapView - Create a 2D map"
https://developers.arcgis.com/javascript/latest/sample-code/sandbox/index.html?sample=intro-mapview

Change code inside script to this:
require([
      "esri/Map",
      "esri/views/MapView",
      "esri/layers/MapImageLayer"
    ], function(Map, MapView, MapImageLayer) {

      var layer = new MapImageLayer({
        url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/SampleWorldCities/MapServer'
      });

       var map = new Map({
          layers: [layer]
        });

      var view = new MapView({
        container: "viewDiv",
        zoom: 4,
        map: map,
        center: [15, 65] // longitude, latitude
      });
    });

Thanks

Arne Dahlman

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Anne,

   Strange. So I tested exactly what you specified in your post and the map drew fine for me in Chrome

Version 70.0.3538.110 (Official Build) (64-bit)

0 Kudos
ArneDahlman
New Contributor III

Thank you for your reply Robert.
Yes this is strange. I use the same version of Chrome as you.

However, I think I found a workaround.
view.Goto after view is ready seems to fix the problem.


 require([
      "esri/Map",
      "esri/views/MapView",
      "esri/layers/MapImageLayer"
    ], function(Map, MapView, MapImageLayer) {

      var layer = new MapImageLayer({
        url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/SampleWorldCities/MapServer'
      });

       var map = new Map({
          layers: [layer]
        });

      var view = new MapView({
        container: "viewDiv",
        zoom: 4,
        map: map,
        center: [15, 65] // longitude, latitude
      });

      view.when(function(){
        view.goTo(view.extent.clone());
        }, function(error){
      });     
    });


I think there is a bug here. Maybe it's some kind of race-condition?

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

 I agree this seems to work for Sebastian's examples too.

      document.querySelector(".btns").addEventListener("click", function(
        event) {
        /************************************************************
         * On a button click, change the map of the View
         ************************************************************/
        var id = event.target.getAttribute("data-id");
        if (id) {
          var map = maps[id];
          view.map = map;
          watchUtils.whenOnce(view, "ready").then(
            function(){
               view.goTo(view.extent.clone());
            }
          )

          var nodes = document.querySelectorAll(".btn-switch");
          for (var idx = 0; idx < nodes.length; idx++) {
            var node = nodes[idx];
            var mapIndex = node.getAttribute("data-id");
            if (mapIndex === id) {
              node.classList.add("active-map");
            } else {
              node.classList.remove("active-map");
            }
          }
        }
      });
0 Kudos
SebastianKvist
New Contributor II

Thank you Robert and Arne.

I provide the original example with applied workarounds from you both and some additions. To get it to work in all use cases with v4.8+, I had to do the following (please note the two "workaround"-comments):

require([
      "esri/views/MapView",
      "esri/Map",
      "esri/layers/MapImageLayer",
       "esri/core/watchUtils"
    ], function(
      MapView, Map, MapImageLayer, watchUtils
    ) {

      var mapConfigs = [
        {}, 
        {}, 
        {}
      ];

      /************************************************************
       * Create multiple map instances, each with one 
        * MapImageLayer-instance added to it..
       ************************************************************/
      var maps = mapConfigs.map(function(mapConfig) {
        var map = new Map(mapConfig);
        map.add(new MapImageLayer({
          url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/SampleWorldCities/MapServer'
        }));
        return map;
      });

      /************************************************************
       * Initialize the View with the first Map
       ************************************************************/
      var view = new MapView({
        map: maps[0],
        container: "viewDiv"
      });
       
       // Workaround for v4.8+
       view.when(function() {
          view.goTo(view.extent.clone());
       });

      document.querySelector(".btns").addEventListener("click", function(
        event) {
        /************************************************************
         * On a button click, change the map of the View
         ************************************************************/
        var id = event.target.getAttribute("data-id");
        if (id) {
          var map = maps[id];            
          view.map = map;
            
            // Workaround for v4.8+
            watchUtils.whenTrue(view, "ready", function() {
               watchUtils.whenTrueOnce(view, "stationary", function() {
                 view.goTo(view.extent.clone());
               });
          });

          var nodes = document.querySelectorAll(".btn-switch");
          for (var idx = 0; idx < nodes.length; idx++) {
            var node = nodes[idx];
            var mapIndex = node.getAttribute("data-id");
            if (mapIndex === id) {
              node.classList.add("active-map");
            } else {
              node.classList.remove("active-map");
            }
          }
        }
      });
    });

If I go back to 4.7 - i can inactivate the two commented workaround sections and see the mapView loaded both initially and when switching between the different map-objects. Using 4.8 or later, I find that I need the first workaround section to trigger the initial data-fetching for the default map object. The second workaround section is needed for when I swap the map object. Note that it is a nested watcher, it wasn't sufficient with just 'stationary' or 'ready' - but a combination of both..

Its an acceptable workaround, even if the user experience differ somewhat (was a smoother and somewhat faster switch with 4.7).

Thanks again!

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Strange. I did not need any workaround in 4.9 to get the initial map to display and I only needed the code I provided to make the map change work for me. Either way it is a bug in 4.8+ like you say. Have you reported this to esri tech support?

0 Kudos