When are layers done?

I’ve seen this question pop up a couple of times in regards to the ArcGIS API for JavaScript. The question is usually along the lines of When is the layer done drawing? That’s a valid question, so let’s talk about it.

If we look at the Programming Patterns documentation, we can see that we’ll probably want to watch for some property changes to happen. The big question is, which properties?

Some fundamentals

You are most likely interested in when a FeatureLayer has not only loaded the data it currently needs, but also when that data has been drawn on the map. If we look at the Map and Views guide, we can see that the map and layers are basically data models for our applications. They don’t actually draw anything, so we most likely don’t want to interact with them directly if we are interested in when they are done drawing.

It’s important to note how the flow of data to what you see works.

Map -> View -> LayerViews

For every layer in a map, a LayerView is created. The LayerView is in charge of determining what data it needs to ask the layer to fetch and taking the renderer information and drawing that data. For a FeatureLayer, you would have a FeatureLayerView. Now, if you are interested when data is done drawing on the map, this is what you are looking for!

FeatureLayerView

There are a couple of ways to get the LayerViews of the MapView or SceneView. You can use the whenLayerView() method, or listen for the layerview-create event. I prefer to be specific and use the whenLayerView method, so I know what I’m getting.

view.whenLayerView(featureLayer)
  .then((layerView) => {
    return watchUtils.whenFalseOnce(layerView, 'updating');
  })
  .then((newValue, oldValue, prop, layerView) => {
    console.log('layerView is done loading and drawing', layerView);
  });

The key is to watch for the layerView.updating property to be false. When it’s false, that means the LayerView is done fetching data and done drawing that data.

You could also do this using async/await!

async function whenDone() {
  const layerView = await view.whenLayerView(featureLayer);
  await watchUtils.whenFalseOnce(layerView, 'updating');
  console.log('layerView is done loading and drawing', layerView);
}

Most of the time, I’m interested in just the first time the layer loads in an application, so I use whenFalseOnce of the watchUtils to check the first time it happens. If you are interested in every time the LayerView is done updating, you could use whenFalse to keep an eye on it.

If I’m interested in checking on a couple of layers, I could use Promise.all to find out when both are done and also watch for any more changes.

  let layerView1
  let layerView2;
  Promise.all([
    view.whenLayerView(fLayer),
    view.whenLayerView(fLayer2)
  ]).then(([lyrView1, lyrView2]) => {
      layerView1 = lyrView1;
      layerView2 = lyrView2;
      return Promise.all(
        [
          whenFalseOnce(layerView1, "updating"),
          whenFalseOnce(layerView2, "updating")
        ]
      );
  }).then(() => {
    console.log("all layerViews done updating");
    whenFalse(layerView1, "updating", () => {
      console.log("layerView1 has updated");
    });
    whenFalse(layerView2, "updating", () => {
      console.log("layerView2 has updated");
    });
  });

You can see what this example looks like here.

This example is interesting because if you zoom out so one of the layers is no longer drawn, you can see that the LayerView updating property will not change, because it does not need to fetch or draw anything.

Console logs of LayerViews

Summary

You may not always need the fine-grained control of knowing when layers are done fetching data or when that data is drawn on the map, but you can! The LayerViews are powerful tools in the ArcGIS API for JavaScript. They manage your layers and when things are drawn, so keep that in mind and you can do some cool stuff! Because they are in charge of drawing your data, you can also apply filters and effects!

Have fun and happy map hacking!