watch for layers being turned on/off (4.3)

3012
4
Jump to solution
05-28-2017 04:04 PM
DataSteward
New Contributor III

I need to run a little code everytime a layer is turned on or off.  Users will control layers through a LayerList widget.  I've seen another post on watching layer lists(https://community.esri.com/message/683587-watch-on-layerlist-not-working-43?q=watch ), but it doesn't seem to cover what I need.  I've also tried map.layers.on("change", function(){ ... }); and about everything else I can think of, but just can't trigger a response when I click a layer on or off.  Thanks for your suggestions!

Tags (3)
0 Kudos
1 Solution

Accepted Solutions
ThomasSolow
Regular Contributor

.on('changes'... will only work on items being added, removed, or moved.  If you're just concerned with visibility, you need to watch the visible property on each layer.  Here's an example of how you might do this: JS Bin - Collaborative JavaScript Debugging

There's a few things to note here:

I'm watching for changes on the map.layers collection, because a layer might be added or removed from the map, in which case I want to start watching its visible property (if added) or remove an old watcher (if removed).

I'm using a Map to keep track of watchers.  This is just a convenient way to associate a layer to a watcher.  You don't have to do this if you don't care about cleaning up old watchers.

I'm using the esri/core/watchUtils watch method in order to check for changes on the visible property on each layer.

You can test this by clicking on the eye icons in the layer list and looking at the console, it should print the layer name and its visibility when it changes.  If you want to include basemaps, just change map.layers to map.allLayers everywhere you see it in the sample.

View solution in original post

4 Replies
MirHashmi
Occasional Contributor

Hi,

There is this sandbox sample "Watch For Changes".  I believe, this snippet taken from the same sample should work for you too.  Still if it doesn't work then i think there could be some other error in script that is preventing this event to trigger.

// Listen to layer change events on all of map's layers 
      // Only listening to layer added event in this case. 
      map.allLayers.on("change", function(event) {
        // change event fires after an item has been added, moved or removed from the collection. 
        // event.moved - an array of moved layers
        // event.removed - an array of removed layers
        // event.added returns an array of added layers  
        if (event.added.length > 0) {
          event.added.forEach(function(layer) {
            var info = "<br> <span> layer added: </span> " + layer.title;
            displayMessage(info);
          });
        }
      });
0 Kudos
DataSteward
New Contributor III

Thanks! But... I don't believe that will work.  I've tried adding that code and similar, but am getting no response.  My console does not indicate any javascript errors.

      map.allLayers.on("change", function(event) {
        alert('allLayers change');
      });

The reason I don't think that code is relevant is that it is detecting change on map.allLayers but the changes I'm looking for are about visibility of the layers within the map.  Turning a layer off from the layerList widget doesn't 'remove' it from the map, it just sets its visibility to false.  The sandbox example unfortunately just demonstrates detecting the initial inclusion of a layer in the map, not subsequent client-triggered changes to map layers.

Thus I've tried watching map.layers but that doesn't detect the changes to visibility either.  I'm not finding the watch system to be very intuitive... should I apply a watch to each layer individually?  And if so, how?  I'm using both FeatureLayers and ImageLayers.  I'd also like to detect a change to the basemap.

Thanks!

0 Kudos
ThomasSolow
Regular Contributor

.on('changes'... will only work on items being added, removed, or moved.  If you're just concerned with visibility, you need to watch the visible property on each layer.  Here's an example of how you might do this: JS Bin - Collaborative JavaScript Debugging

There's a few things to note here:

I'm watching for changes on the map.layers collection, because a layer might be added or removed from the map, in which case I want to start watching its visible property (if added) or remove an old watcher (if removed).

I'm using a Map to keep track of watchers.  This is just a convenient way to associate a layer to a watcher.  You don't have to do this if you don't care about cleaning up old watchers.

I'm using the esri/core/watchUtils watch method in order to check for changes on the visible property on each layer.

You can test this by clicking on the eye icons in the layer list and looking at the console, it should print the layer name and its visibility when it changes.  If you want to include basemaps, just change map.layers to map.allLayers everywhere you see it in the sample.

DataSteward
New Contributor III

Thanks - that gave me what I needed!  I've implemented it just a little differently.  For the record...

require([
  "esri/Map",
  "esri/views/MapView",
  "esri/geometry/Extent",
  "esri/core/watchUtils",
  ...
  ],
  function(Map,
    MapView,
    Extent,
    watchUtils,
    ...
    ) {
      
    var map = new Map({
      basemap: "topo",
      });
    
    var view = new MapView({
      container: "map-container",
      map: map,
      ...
      });
 
    //dpLayers brings a set of layers with their details from
    //a database via JSON.  mapLayers is an array I keep for various
    //reference purposes, but is very handy for adding the watches I
    //was asking about in this post
    var mapLayers = [];
    var dpLayersLen = dpLayers.length;
    for (var i = 0; i < dpLayersLen; i++) {
      switch (dpLayers.layerType) {
        case 'raster':
          var imgLayer = new ImageryLayer({
            title: dpLayers.title,
...
           });
          mapLayers.push(imgLayer);
          map.add(mapLayers);
          break;
        case 'vector':
          var featureLayer = new FeatureLayer({
            title: dpLayers.title,
...
            });
          mapLayers.push(featureLayer);
          map.add(mapLayers);
          break;
        }
      }


    var c = mapLayers.length;
    for (var i = 0; i < dpLayersLen; i++) {
      watchUtils.watch(mapLayers, 'visible', function () { alert('Layer visibility changed!')});
      }