#goTo() MapView cannot be used before it is ready

4167
6
11-01-2017 07:08 AM
MichaelLodes2
Occasional Contributor

Hello together,

I tried to zoom on a layer (containing 1 single point) in my MapView and got an error in the web console:

#goTo() MapView cannot be used before it is ready

See a code snippet below. Where's the problem?

var zoomLayer = new FeatureLayer({...});

var view = new MapView({...});

view.then(goToLayer(zoomLayer));

function goToLayer(zoomLayer) {  
 view.goTo(zoomLayer.graphics);  
}

Thank you,

Best Regards

Michael

0 Kudos
6 Replies
RobertScheitlin__GISP
MVP Emeritus

Michael,

  In your goToLayer function is your zoomLayer null or is it ready by then?

function goToLayer(zoomLayer) {
  if(zoomLayer && zoomLayer.graphics){
    view.goTo(zoomLayer.graphics);
  }  
}
MichaelLodes2
Occasional Contributor

There is one Point feature in the layer. It was added to the layer by the push()-method. This one feature is displayed in map, so the layer can't be null (or what do you mean with "being ready"?).

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Michael,

  It is VERY possible that the view is ready before the layer is fully loaded. Did you try the code I provided?

0 Kudos
ThomasSolow
Occasional Contributor III

I believe this is getting changed in 4.6 so that the view will wait until it's ready and then goTo as opposed to throwing that error.

I'm not 100% sure you can goTo a layer off the top of my head, but you might try

featureLayer.then(fl => view.goTo(fl.fullExtent));

assuming your layer has an extent set on it.

JeremyHazel1
New Contributor

I'm going to resurrect this thread as I'm having a similar problem.  I am getting the same error but only in my test cases.  I am using Karma as the test runner and Jasmine as the testing framework.  I believe that because there is no map/mapView in a UI, that the mapView never becomes ready. 

In the zoomtoExtentforFeatureLyr method when the mapView.goTo method is called, the mapView is not ready.  I have gotten by a similar scenario in testing when using featureLayer.when() by watching the layers collection to be updated and programmatically calling the load() method on the feature layer, thus triggering the .when() method which allows the code within that block to be executed and therefore tested.  I do not see something similar to the load() method of the feature layer for the map view in which I can programmatically 'ready' it so that I can execute the test case successfully.

I'm hoping maybe Robert or Thomas may have some insight.

The code is a bit complex but here it is...

Method to be tested...

zoomtoExtentforFeatureLyr(mapView: any, featLyr: any) {
   return new Promise((resolve, reject) => {
      let expand = featLyr.fullExtent.expand(1.5); //expand extent
      mapView.goTo(expand).then(() => { //go to expanded extent
         resolve({ messageCode: 1003, message: "Success" });
       }).catch((err) => {
         reject({ messageCode: 2251, message: "Layer is not part of the view or the layer type is not supported in this view", error: err });
       });
   });
}

Test setup and test case...

describe('Test zoomtoExtentforFeatureLyr Method of esriHelper class', function () {
   let modules: string[];
   let featLyrZoom;

   beforeAll(async (done) => {
      modules =
         [
            "esri/Map",
            "esri/views/MapView",
            "esri/tasks/support/Query",
            "esri/tasks/QueryTask",
            "esri/Graphic",
            "esri/layers/FeatureLayer",
            "esri/layers/GraphicsLayer",
            "esri/widgets/Sketch/SketchViewModel",
            "esri/geometry/Polyline",
            "esri/symbols/SimpleLineSymbol",
            "esri/symbols/SimpleFillSymbol",
            "esri/symbols/SimpleMarkerSymbol",
            "esri/renderers/SimpleRenderer"
         ]
      let appContainerID = 'th-gisContainer';
      this.createDiv(appContainerID);
      await this.initEsriComponents(modules).then(async () => {
         //loading api on testharness div th-gisContainer
         this.loadTemplate(appContainerID);

         let map = new apiGlobals.oEsriMap({
            basemap: "dark-gray"
         });
         mapTest = map;
         // Create new view and assign map to it
         let view = new apiGlobals.oEsriMapView({
            map: mapTest,
            container: 'gis-map',
            extent: {
               xmax: -8515074.16,
               xmin: -8521762.40,
               ymax: 4729308.30,
               ymin: 4723728.40,
               spatialReference: 3857
            },
            logo: false
         });
         mapViewTest = view;
         let graphics = [
         {
            geometry: {
               type: "polygon",
               rings: [
                  [
                     [-10545562.9846, 4679074.550700001],
                     [-10545562.6879, 4679102.904600002],
                     [-10545552.0762, 4679244.839299999],
                     [-10545559.133, 4679443.138599999],
                     [-10545559.0103, 4679524.848099999],
                     [-10545555.8478, 4679533.2465],
                     [-10545530.2572, 4679541.235299997],
                     [-10545448.8329, 4679538.613700002],
                     [-10545432.0929, 4679531.427299999],
                     [-10545432.6999, 4679519.741800003],
                     [-10545432.0881, 4679487.2381],
                     [-10545425.338, 4679481.527900003],
                     [-10545407.9546, 4679484.3605],
                     [-10545390.5071, 4679483.858599998],
                     [-10545378.651, 4679471.575400002],
                     [-10545369.2853, 4679459.247500002],
                     [-10545354.9234, 4679446.178999998],
                     [-10545352.0835, 4679416.552000001],
                     [-10545348.9814, 4679251.669299997],
                     [-10545364.4977, 4679188.474699996],
                     [-10545341.6812, 4679159.553900003],
                     [-10545348.4625, 4679058.611900002],
                     [-10545546.9634, 4679061.515699998],
                     [-10545552.82, 4679063.905699998],
                     [-10545558.7249, 4679068.7949],
                     [-10545562.9846, 4679074.550700001]
                  ]
               ],
               spatialReference: {
                  wkid: 102100,
                  latestWkid: 3857
               }
            },
            attributes: {
               OBJECTID: 19,
               gis_id: "{EFB3D7E9-4D69-43E9-AFCB-F410DD9EAB3D}",
               create_date: 1526915362000,
               create_user_name: "28562014011609288800114",
               last_change_date: 1526915362000,
               last_change_user_name: "28562014011609288800114",
               GlobalID: "{6EF088BE-BC74-4742-ACDA-FFC5542C8BC9}",
               calculated_acreage: null
            }
         }]
         let graphicsRenderer = {
            type: "simple",
            symbol: {
               type: "simple-fill",
               color: "red",
               outline: { color: "yellow", width: 2 }
            }
         }
         let fields =
         [
            { name: "OBJECTID", alias: "OBJECTID", type: "esriFieldTypeOID" },
            { name: "gis_id", alias: "gis_id", type: "esriFieldTypeGUID", length: 38 },
            { name: "create_date", alias: "create_date", type: "esriFieldTypeDate", length: 8 },
            { name: "create_user_name", alias: "create_user_name", type: "esriFieldTypeString", length: 50 },
            { name: "last_change_date", alias: "last_change_date", type: "esriFieldTypeDate", length: 8 },
            { name: "last_change_user_name", alias: "last_change_user_name", type: "esriFieldTypeString", length: 50 },
            { name: "GlobalID", alias: "GlobalID", type: "esriFieldTypeGlobalID", length: 38 },
            { name: "calculated_acreage", alias: "calculated_acreage", type: "esriFieldTypeDouble" }
         ];

         featLyrZoom = new apiGlobals.oEsriFeatureLayer({
            id: "DMEGIS",
            layerId: 0,
            title: "DMEGIS",
            spatialReference: { wkid: 3857 },
            source: graphics,
            fields: fields,
            objectIdField: 'OBJECTID',
            geometryType: "polygon",
            renderer: graphicsRenderer, // set the visualization on the layer
         });

         mapTest.watch("layers.length", async (newValue, oldValue) => {
            if (newValue > 0){
               await mapTest.layers.items[0].load();
               done();
            };
         });
         await mapTest.add(featLyrZoom);
      });
      it('2: Zoomed sucessfully', (done) => {
         document.getElementById("th-gisContainer").style.height = '100px';
         this.zoomtoExtentforFeatureLyr(mapViewTest, featLyrZoom).then(res=> {
            expect(res.messageCode).toEqual(1003);
            done();
         });
      });
   });
});

Helper methods....

initEsriComponents(modules) {
   return new Promise((resolve, reject) => {
//Important: Console log is required to load styles. Unable to find workaround
//TODO: Implement appropriate way to load styles in runtime
      const options = {
         dojoConfig: {
            async: false,
            isDebug: true
         }
      };
      this.loadEsriModules(modules, options).then(() => {
         resolve({ messageCode: 1006 });
      }).catch(err => {
         reject({ messageCode: 2351, error: err });
      });
   });
}
/*
* Loading ESRI modules
* input : modules - string[] - passing esri modules from api-conf.json
* input : options - any - passing dojoConfig
* output : setting global variables for esri modules
*
*/
async loadEsriModules(modules: string[], options: any) {
   await loadModules(modules, options).then(
      ([
         Map,
         MapView,
         Query,
         QueryTask,
         Graphic,
         FeatureLayer,
         GraphicsLayer,
         SketchViewModel,
         Polyline,
         SimpleLineSymbol,
         SimpleFillSymbol,
         SimpleMarkerSymbol,
         SimpleRenderer,
         LabelClass
      ]) => {
         Window["apiGlobals"] = apiGlobals;
         apiGlobals.oEsriMap = Map;
         apiGlobals.oEsriMapView = MapView;
         apiGlobals.oEsriQuery = Query;
         apiGlobals.oEsriQueryTask = QueryTask;
         apiGlobals.oEsriGraphic = Graphic;
         apiGlobals.oEsriFeatureLayer = FeatureLayer;
         apiGlobals.oEsriGraphicsLayer = GraphicsLayer;
         apiGlobals.oEsriSketchViewModel = SketchViewModel;
         apiGlobals.oEsriPolyline = Polyline;
         apiGlobals.oEsriSimpleLineSymbol = SimpleLineSymbol;
         apiGlobals.oEsriSimpleFillSymbol = SimpleFillSymbol;
         apiGlobals.oEsriSimpleMarkerSymbol = SimpleMarkerSymbol;
         apiGlobals.oEsriSimpleRenderer = SimpleRenderer;
         apiGlobals.oEsriLabelClass = LabelClass;
      }
   );
}
/*
Loading API Design on Div Id by passing from Test Harness
input : appContainerID - string - To load the gis template
output : true or false - boolean - returning true or false based on gis template load
*/
loadTemplate(appContainerID: string): boolean {
   //Important: Console log is required to load styles. Unable to find workaround
   //TODO: Implement appropriate way to load styles in runtime
   console.log(cssBootstrap);
   console.log(calcitemapsBootstrap);
   console.log(calcitemapsArcGis);
   console.log(esrimainCss);
   console.log(styleBaseTemplate);
   const thgisContainer = document.getElementById(appContainerID);
   //loading template if not exist
   if (
      document.getElementById("gis-wrapperDiv") === null ||
      document.getElementById("gis-wrapperDiv") === undefined
   ) {
         thgisContainer.innerHTML = baseTemplate.toString();
         //CCSAP:10/16/2019 - TODO - Bootstrap responsive design related code coverage not covered
         uiEventsHandler.uiEventsHandler($, bootstrap);
         return true;
   } else {
      return false;
   }
}
createDiv(divid: string): boolean {
   let body: HTMLBodyElement = document.getElementsByTagName("body")[0];
   let element: HTMLDivElement = document.createElement('div');

   if (divid === 'th-gisContainer' || divid === apiConfig["gisWrapperDiv"]) {
      element.id = divid;
      element.style.height = '100px';
      element.style.width = '100px';
      body.appendChild(element);
   return true;
   }else {
      return false;
}

baseTemplate...

<div id="gis-wrapperDiv" class="calcite-maps calcite-nav-top block my-modal" style="height:100%">

   <!-- Processing Modal -->
   <div id="gis-processingModal" class="modal fade" tabindex="-1" role="dialog">
      <div class="modal-dialog modal-dialog-centered" role="document">
         <div class="modal-content">
            <div class="modal-body text-center">
               <div class="processing"></div>
               <div clas="processing-txt">
                  <p id="gis-processingTxt">Processing.... </p>
               </div>
            </div>
         </div>
      </div>
   </div>


   <!-- Map -->
   <div id="gis-map" style="position:relative;width:100%;height:100%;"></div>

</div>
<!--gis-wrapperDiv-->
0 Kudos
JeremyHazel1
New Contributor

And...disregard.  I was able to get the test case working properly by setting the height of the container in the test case itself so that the map view became 'ready'.