Widget to turn on/off layers? (No, not the Layerlist.)

2719
12
12-17-2019 12:25 PM
Arne_Gelfert
Occasional Contributor III

As noted in another post just minutes ago, I'm in the process of converting some existing custom Geocortex tools to ESRI WAB or JSAPI web functionality.

Geocortex offers the apparently rather popular Themes concept in their framework. It's a way to group a number of layers into a theme and then turn layers on/off by switching from one theme to another. So you'd either pick a selection from a dropdown, or with only two choice toggle between two states to activate (turn on) one group layers, thereby turning the other(s) off. QUESTION: Is there an obvious OTB or available custom widget candidate to do this?

Certainly don't want to make anyone have to interact with the LayerList or TOC to hide or unhide layers. it should be more one-click behavior. I could see how you'd build two web maps from map services in Portal and then flip back and forth between those.

It's quite easy to build this using the JavaScript API. All you need is a HTML dropdown element with some event handlers that then turn on/off layers. Unfortunately, I have not been able to twist my brain into a shape that would allow me to decipher custom WAB widgetry . So hoping that someone has used one of the available widgets for this purpose?

Thanks!

0 Kudos
12 Replies
RobertScheitlin__GISP
MVP Emeritus

Arne,

   You will want to look at using this widget. It allows you to click the widget button and turn on/off one or more layers in the map.

https://community.esri.com/docs/DOC-8592-layer-toggle-button-widget-version-212-08282019 

Arne_Gelfert
Occasional Contributor III

Thanks, Robert... I stumbled upon this after posting my question and looked at your sample. Sounds like this might do the trick. Stay tuned... I may have some questions on how to tweak his. 

0 Kudos
Arne_Gelfert
Occasional Contributor III

Okay, your LayerToggleButton works like a charm. Now, let me ask you this: Would this be a good candidate to heed your repeated advice and encouragement to dig into the jimu jambalaya to adapt for my purposes? 

If I wanted to change the behavior to be:

  • Use a dropdown widget: Basically you pick your layer or group of layers from a dropdown.
  • Selection of that layer(s) turn on that layer(s) and turn of all other layers

What changes would be needed? I'm assuming...

  • LayerSelector.html would need to get a dropdown. I'm not familiar with all the dojo/jimu elements but I can figure it out.
  • LayerSelector.js - I can't even begin to wrap my brain around this yet. A lot of this is just needed to make the widget configurable, right? I suspect, there would have to be a way to name your elements for the dropdown and assign layers to each, provided it's not a 1:1 but groups of layers getting assigned to one dropdown item. How much of this could be gutted if I didn't need it to be configurable but was able to just hard code which layers correspond to which element in a list of dropdown items that i define?

Have you ever considered writing a book about all this? Seems like based on all the Geonet posts of yours I have read, you'd be the right one to do it. I find that without some decent tutorial, I will never have enough cycles to dedicate to this, and will likely have to get some outside help. Which is a huge disappointment in ESRI. But you have to be realistic. Anyway, I'll go through the code with a fine tooth comb and see what nuggets I can tease out of you with my next post. 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Arne,

   So the whole LayerSelector portion of the widget is just for widget configure-ability in the widget settings UI. If you want to hard code the layers that will be toggled then you do not need that at all. So the biggest thing you need to do is create a widget.html and widget.js that has a dropdown and then wire up the change event to fire off the code to toggle the layers based on the selected value. So consider that the layer toggle widget has very little code that actually does the toggling. In the toggleLayer method is where the real work occurs. I use the LayerStructure class—Web AppBuilder for ArcGIS (Developer Edition) | ArcGIS for Developers to traverse all layers and hide them then I use lObjs array to that get populated in the onOpen method to 

lObj.toggle();

In the onOpen I use layerStructure.getNodeById to get the layer object based on the layer object id in the config.json of the widget. 

var lObjs = [];
        array.map(this.toggleLayerIdslang.hitch(thisfunction(id){
          var lyrNode = this.layerStructure.getNodeById(id);
          lObjs.push(lyrNode);
        }));

So each layer has an id assigned to it in the WAB map (this is Not the name of the layer or something simple you would know). I.e.

"LOJIC_LandRecords_Louisville_4356"

You can find these ids by inspecting the LayerList widget dom using developer tools.

So first things first.

  1. build your widgets UI with a drop down.
  2. have a change event on the drop down.
  3. have that change event based on the value of the drop down show or hide layers using a if statement or a js switch statement.

The gotchas to look out for when you get to the actual showing or hiding the layers is that if the layer is visible and you call 

lObj.show();

This causes an issue in the code. So don't call show() or hide() on a layer that is already in that visible state.

Good luck

Arne_Gelfert
Occasional Contributor III

That was great. I will start sifting through all this tomorrow. Thanks for sharing your insights and making this mystery accessible!

0 Kudos
Arne_Gelfert
Occasional Contributor III

Robert Scheitlin, GISP, 3 weeks on, and I'm finally getting back to this. I read over your instructions up there, and I think I hear what you're saying. It's just still seems too much at once for my first round of widgetry.

So instead, I'm starting with this for widget.html and using dijit/form/Select

<div>
    <select name="LayerSelector" data-dojo-type="dijit/form/Select">
      <option value="First Layer">First Layer</option>
      <option value="Second Layer">Second Layer</option>
    </select> 
</div>‍‍‍‍‍‍‍‍‍‍‍‍‍

That gives me this:

Great! Then I used the Demo widget as template, added the Mixin's for the dojo dropdown

define(['dojo/_base/declare', 
'jimu/BaseWidget',
'dijit/_WidgetsInTemplateMixin'
],
function(declare, 
     BaseWidget,
    _WidgetsInTemplateMixin
   ) {
return declare([BaseWidget,_WidgetsInTemplateMixin], {
   baseClass: 'jimu-widget-layerselector',
[...]

I also kept the following life cycle methods - bare, with only console logging:

postCreate: function() {
this.inherited(arguments);
console.log('postCreate');
},
  
startup: function() {
this.inherited(arguments);
console.log('startup');
},
  
onOpen: function(){
console.log('onOpen');
},
  
onClose: function(){
console.log('onClose');
}

Then I added an event handler (merely to log the event), based on this other thread where you chimed in.

cbChangedHandler: function (who, property, oldValue, {
   console.info(who, property, oldValue, newValue);
}

Now, how do I rig this up with a event listener? Again, I found the following snippet in your other example:

this.LayerSelector.watch('displayedValue', lang.hitch(this, this.cbChangedHandler, "LayerSelector"));

But where does it need to live? Am I generally still on track to widget enlightenment or lost in the woods? 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Widget startup function would be a good place.

0 Kudos
Arne_Gelfert
Occasional Contributor III

That was the first thing I tried, and I get this:

init.js:115 TypeError: Cannot read property 'watch' of undefined
 at Object.startup (Widget.js?wab_dv=2.14:25)
 at Object.advice (init.js:121)
 at Object.c [as startup] (init.js:120)
 at Object.<anonymous> (BaseWidgetPanel.js?wab_dv=2.14:83)
 at init.js:64
 at m (init.js:108)
 at k (init.js:108)
 at e.resolve (init.js:110)
 at Object.<anonymous> (WidgetManager.js?wab_dv=2.14:131)
 at init.js:64 "TypeError: Cannot read property 'watch' of undefined
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Arne,

   Because the select object needs a data-dojo-attach-point attribute.

<select data-dojo-attach-point="LayerSelector" data-dojo-type="dijit/form/Select">
0 Kudos