Select to view content in your preferred language

LayerList wdiget listen to layer changes

491
5
Jump to solution
06-08-2023 04:34 AM
Aeseir
by
Occasional Contributor

i created a layerlist widget as so:

 

this.layerList = new LayerList({
      view: this.view,
      selectionEnabled: true,
    });

 

and then added it to ui.

 

I have bunch of featurelayers, mapimagelayers,grouplayers etc now loaded on the map.

 

The user rearranges the layer in the widget list as they choose fit, is it possible to find out which layer was changed?

1 Solution

Accepted Solutions
Sage_Wall
Esri Contributor

Hi @Aeseir take a look at this codepen, hopefully it will get you started in the right direction.  I wasn't sure exactly what properties on the layer you were interested in so I just used the layer title and index in the example.

 

require([
  "esri/WebMap",
  "esri/views/MapView",
  "esri/core/Collection",
  "esri/core/reactiveUtils",
  "esri/widgets/LayerList"
], (WebMap, MapView, Collection, reactiveUtils, LayerList) => {
  const changesList = document.querySelector("#changesList");

  const map = new WebMap({
    portalItem: {
      id: "512944c00f8a4219a4bb70691089c9e9"
    }
  });

  const view = new MapView({
    container: "viewDiv",
    map
  });

  const layerList = new LayerList({
    selectionEnabled: true,
    view
  });

  view.ui.add(layerList, "top-right");

  let previousTitles = new Collection();

  reactiveUtils.watch(
    () => view.map.allLayers.map((layer) => layer.title),
    (titles) => {
      const areTitlesEqual = detectChanges(previousTitles, titles);
      if (!areTitlesEqual) {
        whatChanged(previousTitles, titles);
      }
      previousTitles = titles;
    }
  );

  function detectChanges(
    firstCollection: Collection,
    secondCollection: Collection
  ) {
    if (firstCollection.length === secondCollection.length) {
      firstCollection.forEach((item, index) => {
        if (item === secondCollection.getItemAt(index)) {
          return true;
        }
        return false;
      });
    }
    return false;
  }

  function whatChanged(
    firstCollection: Collection,
    secondCollection: Collection
  ) {
    changesList!.innerHTML = "";
    firstCollection.forEach((item, index) => {
      if (item !== secondCollection.getItemAt(index)) {
        const listItem = document.createElement("calcite-list-item");
        listItem.label = item;
        listItem.description = `previously at index ${index} moved to index ${secondCollection.findIndex(
          (secondItem) => secondItem === item
        )}`;
        changesList!.appendChild(listItem);
      }
    });
  }
});

 

View solution in original post

0 Kudos
5 Replies
Sage_Wall
Esri Contributor

Hi @Aeseir , you can use reactiveUtils to watch the map's `layers` or `alllayers` collections. We don't have an example available that shows this exact use case but the documentation shows how to watch collections and how to compare to previous values.  There is also a lot of really good info in this sample. https://developers.arcgis.com/javascript/latest/sample-code/watch-for-changes-reactiveutils/  If I get time I'll try and write a codepen.

0 Kudos
Aeseir
by
Occasional Contributor

hi @Sage_Wall thanks for reaching out, that was the first place I went to see if i can figure it out, but haven't yet figured it out.

If you can find time to put together a simple codepen to show at your convenience, would be amazing.

I'll keep experimenting in meantime.

0 Kudos
Sage_Wall
Esri Contributor

Happy to help when I can, its been really busy around here this week preparing for the 4.27 release.  Hopefully I'll get a moment today to write an example

0 Kudos
Sage_Wall
Esri Contributor

Hi @Aeseir take a look at this codepen, hopefully it will get you started in the right direction.  I wasn't sure exactly what properties on the layer you were interested in so I just used the layer title and index in the example.

 

require([
  "esri/WebMap",
  "esri/views/MapView",
  "esri/core/Collection",
  "esri/core/reactiveUtils",
  "esri/widgets/LayerList"
], (WebMap, MapView, Collection, reactiveUtils, LayerList) => {
  const changesList = document.querySelector("#changesList");

  const map = new WebMap({
    portalItem: {
      id: "512944c00f8a4219a4bb70691089c9e9"
    }
  });

  const view = new MapView({
    container: "viewDiv",
    map
  });

  const layerList = new LayerList({
    selectionEnabled: true,
    view
  });

  view.ui.add(layerList, "top-right");

  let previousTitles = new Collection();

  reactiveUtils.watch(
    () => view.map.allLayers.map((layer) => layer.title),
    (titles) => {
      const areTitlesEqual = detectChanges(previousTitles, titles);
      if (!areTitlesEqual) {
        whatChanged(previousTitles, titles);
      }
      previousTitles = titles;
    }
  );

  function detectChanges(
    firstCollection: Collection,
    secondCollection: Collection
  ) {
    if (firstCollection.length === secondCollection.length) {
      firstCollection.forEach((item, index) => {
        if (item === secondCollection.getItemAt(index)) {
          return true;
        }
        return false;
      });
    }
    return false;
  }

  function whatChanged(
    firstCollection: Collection,
    secondCollection: Collection
  ) {
    changesList!.innerHTML = "";
    firstCollection.forEach((item, index) => {
      if (item !== secondCollection.getItemAt(index)) {
        const listItem = document.createElement("calcite-list-item");
        listItem.label = item;
        listItem.description = `previously at index ${index} moved to index ${secondCollection.findIndex(
          (secondItem) => secondItem === item
        )}`;
        changesList!.appendChild(listItem);
      }
    });
  }
});

 

0 Kudos
Aeseir
by
Occasional Contributor

Thanks @Sage_Wall love your work. I ended up on something similar using a combination of reactiveUtils on list widget and all the layers. Am modifying content to adopt some of your information.

As a recommendation would be great if in future this reactivity was applied at Layer interface as a observable, thus making it event driven. It will make it easier to separate out concerns, and manage change.