Web AppBuilder - Limit Legend Items Based on Filters or Map Extent

3258
16
Jump to solution
04-10-2018 03:47 PM
TessOldemeyer
Occasional Contributor

Is there a way to limit legend items to only those feature values in the current extent in a Web AppBuilder (Developer's Edition 2.7) app? I currently have a service layer symbolized by unique values for my attribute of interest, though as I zoom to features, it would be nice to limit the legend to show only the unique values that are currently displayed (rather than having to browse through the many many unique values that are symbolized for the layer within the legend). I am using the filter widget to filter and zoom to features based off of multiple expressions for unique values and previous expression filters. Maybe limiting legend contents would need to be configured within the original map document, the service, the Portal web map, or in the application itself? I have attempted to achieve this functionality with the Legend and Layers widgets and have not had any luck. I'm curious as to what steps I may need to take to establish this functionality. 

Thanks in advance!


Tess

1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Tess,

   This is something that several people have asked for but, it is not available. The amount of code would be large to make this happen as the extent change event would have to be listened for and then a query of each layer that is in the map extent would have to be done and then the Legends layerInfos would have to be updated and that would only remove a whole layer that is not inside the extent that would not even cover a unique val of a renderer that is not present in the legend (that is a whole other ball game).

View solution in original post

16 Replies
RobertScheitlin__GISP
MVP Emeritus

Tess,

   This is something that several people have asked for but, it is not available. The amount of code would be large to make this happen as the extent change event would have to be listened for and then a query of each layer that is in the map extent would have to be done and then the Legends layerInfos would have to be updated and that would only remove a whole layer that is not inside the extent that would not even cover a unique val of a renderer that is not present in the legend (that is a whole other ball game).

TessOldemeyer
Occasional Contributor

Good to know. I will look forward to this capability if it may become available in the future. Thanks! 

Tess

0 Kudos
JamalWest2
Occasional Contributor

I have found a way to do this, I haven't had any issues yet. I did this within a report widget . The onSubscribe function runs within the widgets onOpen function. The function to turn layers back on runs after report w/map is created. The DWclick topic runs  the doWork() function.

   

postCreate: function() {
this.inherited(arguments);
this.own(topic.subscribe("DWclick", lang.hitch(this, this.doWork)));
this.own(topic.subscribe("FRclick", lang.hitch(this, this.finReport)));
},



onOpen: function () {

this.onSubscribe();
setTimeout(function() {topic.publish('DWclick');}, 6000);
},



doWork: function () {

//Create and print report

setTimeout(function() {topic.publish('FRclick');}, 3000);

}



onSubscribe: function() {
var extent = this.map.extent
layerlist=[];
LayerInfos.getInstance(this.map, this.map.itemInfo, extent).then(function(layerInfosObject){
layerInfosObject.traversal(function(layerInfo) {
if (layerInfo._visible) {
if(layerInfo.title!=="QV_Utility" && layerInfo.title!=="Ticket Symbols" && layerInfo.title!=="Closed Tickets" && layerInfo.title!=="Emergency Tickets" && layerInfo.title!=="Open Tickets" ){
var fullrl = layerInfo.layerObject.url;
var qt = new QueryTask(fullrl);
var query = new Query();
query.returnGeometry = false;
var OIDfield = layerInfo.layerObject.objectIdField;
query.where = "1=1";
query.geometry = extent;
var countDef = layerInfo.layerObject._currentDef = qt.executeForCount(
query,
lang.hitch(layerInfo.layerObject, function(results) {

if (results){


return results;
}
else{
if (results==0) {
//console.log("-This layer:",layerInfo.title,"Is not currently in mapview and must be turned off, it has 0 or undefined# of records.",results);
layerInfo.setTopLayerVisible(false);
layerlist.push(layerInfo.title);
}
}

})
);
}
}
});
});
//this._clearLayers()
//this.showLayers();
//console.log(layerlist);
this.layerlist= layerlist;
return this.layerlist;
PanelManager.getInstance().closePanel('_31_panel');
},

finReport: function(layerlist) {
//console.log("FINREPORT");
console.log("FINREPORT",this.layerlist); 
LayerInfos.getInstance(this.map, this.map.itemInfo).then(function(layerInfosObject){
layerInfosObject.traversal(function(layerInfo) {
if (this.layerlist.includes(layerInfo.title)){
//console.log(layerInfo.title, "will be turned on now");
layerInfo.setTopLayerVisible(true);
}
});
});
},

‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
TessOldemeyer
Occasional Contributor

Thank you so much for this info. I added this code to the widget.js file in a Report dijit widget, and I am hiving issues with mainfest.json errors from the widget. As I have not yet spent much time configuring custom widgets, these errors could be from multiple sources. Would you mind making this widget folder available to download? 

0 Kudos
JamalWest2
Occasional Contributor

None of the other files within the folder would be affected by this change. The only issue you may have is with this line. 

PanelManager.getInstance().closePanel('_31_panel');

You may want to comment this line out as it is not likely a widget Id that is utilized in your app. Also be sure to add dojo/topic module to your require/function section at the top of widget.js.

require(["dojo/topic"], function(topic){

Can you post your error here?

I attached my widget.js file below. You can check it out and replace/add sections to your own widget.js where necessary.

0 Kudos
TessOldemeyer
Occasional Contributor

Thanks again for all of your help Jamal. It turns out I had a syntax error in the manifest.json file that I was able to resolve, so that error is no longer showing up when I start the WAB sartup.bat file. However,  I am currently getting a 'create widget error' after I add the widget via WAB and try to open it. 

I have attached my current 'Report' widget folder. If you can provide any recommendations on where I might need to make modifications, they will be helpful. I apologize that I am new to this type of configuration, and I may be missing some very obvious errors...  

Thanks again!


Tess

0 Kudos
JamalWest2
Occasional Contributor

You'll have to look at the browsers console to see what the errors are. There are a number of reasons that a widget may not open.

0 Kudos
TessOldemeyer
Occasional Contributor

Thanks. This is super helpful and good to go through. This is pretty big and messy.

panel [widgets_Report_Widget_32_panel] created.
17:00:01.993 Widget.js?wab_dv=2.7:2 Uncaught SyntaxError: Unexpected identifier
17:00:02.014 WidgetManager.js?wab_dv=2.7:116 create [widgets/Report/Widget] error:TypeError: clazz is not a constructor
at Object.createWidget (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/WidgetManager.js?wab_dv=2.7:320:16)
at Object.<anonymous> (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/WidgetManager.js?wab_dv=2.7:112:35)
at https://jsdev.arcgis.com/3.23/init.js:63:337
at h (https://jsdev.arcgis.com/3.23/init.js:107:277)
at q (https://jsdev.arcgis.com/3.23/init.js:107:203)
at d.resolve (https://jsdev.arcgis.com/3.23/init.js:109:280)
at Object.<anonymous> (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/WidgetManager.js?wab_dv=2.7:189:13)
at https://jsdev.arcgis.com/3.23/init.js:63:337
at h (https://jsdev.arcgis.com/3.23/init.js:107:277)
at q (https://jsdev.arcgis.com/3.23/init.js:107:203)

Widget.js?wab_dv=2.7:127 Uncaught TypeError: Cannot read property 'name' of undefined
at Object._onWidgetCreation (VM3435 Widget.js:127)
at Object.<anonymous> (VM2999 init.js:63)
at Object.c [as onwidget-created] (VM2999 init.js:119)
at Function.h.emit (VM2999 init.js:124)
at Function.h.emit (VM2999 init.js:125)
at Object.emit (VM2999 init.js:117)
at Object.<anonymous> (VM3326 WidgetManager.js:131)
at VM2999 init.js:63

init.js:114 TypeError: clazz is not a constructor
at Object.createWidget (VM3326 WidgetManager.js:320)
at Object.<anonymous> (VM3326 WidgetManager.js:112)
at VM2999 init.js:63
at h (VM2999 init.js:107)
at q (VM2999 init.js:107)
at d.resolve (VM2999 init.js:109)
at Object.<anonymous> (VM3326 WidgetManager.js:189)
at VM2999 init.js:63
at h (VM2999 init.js:107)
at q (VM2999 init.js:107) "TypeError: clazz is not a constructor
at Object.createWidget (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/WidgetManager.js?wab_dv=2.7:320:16)
at Object.<anonymous> (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/WidgetManager.js?wab_dv=2.7:112:35)
at https://jsdev.arcgis.com/3.23/init.js:63:337
at h (https://jsdev.arcgis.com/3.23/init.js:107:277)
at q (https://jsdev.arcgis.com/3.23/init.js:107:203)
at d.resolve (https://jsdev.arcgis.com/3.23/init.js:109:280)
at Object.<anonymous> (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/WidgetManager.js?wab_dv=2.7:189:13)
at https://jsdev.arcgis.com/3.23/init.js:63:337
at h (https://jsdev.arcgis.com/3.23/init.js:107:277)
at q (https://jsdev.arcgis.com/3.23/init.js:107:203)
----------------------------------------
rejected at a (https://jsdev.arcgis.com/3.23/init.js:108:174)
at h (https://jsdev.arcgis.com/3.23/init.js:107:450)
at q (https://jsdev.arcgis.com/3.23/init.js:107:203)
at d.l.reject (https://jsdev.arcgis.com/3.23/init.js:109:488)
at Object.<anonymous> (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/WidgetManager.js?wab_dv=2.7:125:21)
at https://jsdev.arcgis.com/3.23/init.js:63:337
at h (https://jsdev.arcgis.com/3.23/init.js:107:277)
at q (https://jsdev.arcgis.com/3.23/init.js:107:203)
at d.resolve (https://jsdev.arcgis.com/3.23/init.js:109:280)
at Object.<anonymous> (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/WidgetManager.js?wab_dv=2.7:189:13)
----------------------------------------
Error
at d.then.b.then (https://jsdev.arcgis.com/3.23/init.js:110:97)
at Object.<anonymous> (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/BaseWidgetPanel.js?wab_dv=2.7:76:53)
at Object.forEach (https://jsdev.arcgis.com/3.23/init.js:70:486)
at Object.loadAllWidgetsInOrder (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/BaseWidgetPanel.js?wab_dv=2.7:66:13)
at Object.startup (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/BaseWidgetPanel.js?wab_dv=2.7:55:12)
at Object.g (https://jsdev.arcgis.com/3.23/init.js:197:400)
at Object.startup (https://mydevurl:3344/webappbuilder/apps/2/themes/DartTheme/panels/DartPanel/Panel.js?wab_dv=2.7:56:...)
at Object.openPanel (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/PanelManager.js?wab_dv=2.7:151:17)
at Object.<anonymous> (https://mydevurl:3344/webappbuilder/apps/2/jimu.js/PanelManager.js?wab_dv=2.7:93:16)
at https://jsdev.arcgis.com/3.23/init.js:63:337"


Widget.js?wab_dv=2.7:155 TypeError: Cannot read property 'nodeType' of null
at Object.getComputedStyle (VM2999 init.js:162)
at Object.h.getContentBox (VM2999 init.js:179)
at Object._resizeController (VM3435 Widget.js:145)
at VM2999 init.js:63
17:07:47.215 Widget.js?wab_dv=2.7:155 TypeError: Cannot read property 'nodeType' of null
at Object.getComputedStyle (VM2999 init.js:162)
at Object.h.getContentBox (VM2999 init.js:179)
at Object._resizeController (VM3435 Widget.js:145)
at VM2999 init.js:63
17:07:53.986 Widget.js?wab_dv=2.7:155 TypeError: Cannot read property 'nodeType' of null
at Object.getComputedStyle (VM2999 init.js:162)
at Object.h.getContentBox (VM2999 init.js:179)
at Object._resizeController (VM3435 Widget.js:145)
at VM2999 init.js:63

0 Kudos
JamalWest2
Occasional Contributor

I would go through your code and make sure every section is properly closed. That is usually the issue with clazz constructor. You should be able to click the rrror and see the exact line where it has an issue. Also the last error tells you exactly what file and line the problem is on...
Widget.js?

wab_dv=2.7:155 TypeError: Cannot read property 'nodeType' of null 

line 155 of Widget.js. Use console.log statements to track your codes workflow.