I'm putting together a web app in WAB Developer. it is 95% complete but the last 5% is important. I need a widget that will query a work-order table based on a the user clicking on a feature. There is no spatial info in the work-order table. So it will be on the two relating fields between data sets (upstream manhole, downstream manhole). This limits using relationships, which appears to not be supported in WAB anyway.
I'm starting to learn JS and GIS web dev, but it's a long haul to building my own widgets. Any ideas?
Solved! Go to Solution.
Brad,
This is not WAB widget code but the below is a JS sample that allows for related records query that you may be able to use as a starting point:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"> <title>Test for domain fields in related table</title> <link rel="stylesheet" href="https://js.arcgis.com/3.15/dijit/themes/claro/claro.css" /> <link rel="stylesheet" href="https://js.arcgis.com/3.15/esri/css/esri.css" /> <style> html, body { height: 100%; width: 100%; margin: 0; padding: 0; margin: 0; font-family: "Open Sans"; } #leftPane { width: 20%; margin: 0; border: none; } #map { padding: 0; } </style> <script src="https://js.arcgis.com/3.15/"></script> <script> require([ "dojo/ready", "dojo/on", "dojo/_base/lang", 'esri/tasks/RelationshipQuery', "dojo/dom", "dijit/registry", "dojo/dom-construct", "dojo/parser", "esri/map", "esri/arcgis/utils", "esri/domUtils", "esri/dijit/Popup", "esri/dijit/PopupTemplate", "dijit/layout/BorderContainer", "dijit/layout/ContentPane" ], function ( ready, on, lang, RelationshipQuery, dom, registry, domConstruct, parser, Map, arcgisUtils, domUtils, Popup, PopupTemplate, BorderContainer, ContentPane ) { ready(function () { parser.parse(); //Create a map based on an ArcGIS Online web map id arcgisUtils.createMap("ba61bf1495494336ba347b3286389cd8", "map").then(function (response) { window.map = response.map; this.selectedLayer = map.getLayer(response.itemInfo.itemData.operationalLayers[0].id); this.data = response.itemInfo.itemData.tables[0]; //set the popup's popupWindow property to false. This prevents the popup from displaying map.infoWindow.set("popupWinow", false); initializeSidebar(window.map); }, function (error) { console.log("Map creation failed: ", dojo.toJson(error)); }); function initializeSidebar(map) { var popup = map.infoWindow; //when the selection changes update the side panel to display the popup info for the //currently selected feature. on(popup, "selection-change", function () { displayPopupContent(popup.getSelectedFeature()); }); //when the selection is cleared remove the popup content from the side panel. on(popup, "clear-features", function () { dom.byId("featureCount").innerHTML = "Click to select feature(s)"; registry.byId("leftPane").set("content", ""); domUtils.hide(dom.byId("pager")); }); //When features are associated with the map's info window update the sidebar with the new content. on(popup, "set-features", function () { displayPopupContent(popup.getSelectedFeature()); dom.byId("featureCount").innerHTML = popup.features.length + " feature(s) selected"; //enable navigation if more than one feature is selected popup.features.length > 1 ? domUtils.show(dom.byId("pager")) : domUtils.hide(dom.byId("pager")); }); } function displayPopupContent(feature) { if (feature) { var updateQuery = new RelationshipQuery(); updateQuery.objectIds = [feature.attributes[this.selectedLayer.objectIdField]]; updateQuery.returnGeometry = true; updateQuery.outFields = ["*"]; updateQuery.relationshipId = this.selectedLayer.relationships[0].id; this.selectedLayer.queryRelatedFeatures(updateQuery, lang.hitch(this, function (results) { //If related record found, then set infotemplate of related table if (results[feature.attributes[this.selectedLayer.objectIdField]]) { results[feature.attributes[this.selectedLayer.objectIdField]].features[0].setInfoTemplate(new PopupTemplate(this.data.popupInfo)); //UnComment the following two lines to see proper result //var newLayer = new FeatureLayer(this.data.url); //results[feature.attributes[this.selectedLayer.objectIdField]].features[0]._layer = newLayer; setTimeout(function () { //get content of features and set it to left panel after specified time var content = results[feature.attributes[this.selectedLayer.objectIdField]].features[0].getContent(); registry.byId("leftPane").set("content", content); }, 500); } else { registry.byId("leftPane").set("content", "No Features Found"); } })); } } }); }); </script> </head> <body class="claro"> <div id="mainWindow" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline',gutters:false" style="width:100%; height:100%;"> <div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="gutters:false" region="left" style="width: 40%;height:100%;"> <div id="leftPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div> <div id="header" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'"> <div id="featureCount" style="margin-bottom:5px;">Click to select feature(s)</div> </div> </div> <div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div> </div> </body> </html>
Hi Brad,
I'm trying to work on a similar problem ... I have polygons and points which has relationship classes defined between them. I want a user to click on a polygon, and have the related point feature highlighted on the map. This is for an asset management application. The polygons don't necessarily contain the point within them, so can't build a select by location query. I feel your pain as I don't have the js skills needed to make this work. Sounds like you're close though. I hope someone has some good input for us!
Brad,
This is not WAB widget code but the below is a JS sample that allows for related records query that you may be able to use as a starting point:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"> <title>Test for domain fields in related table</title> <link rel="stylesheet" href="https://js.arcgis.com/3.15/dijit/themes/claro/claro.css" /> <link rel="stylesheet" href="https://js.arcgis.com/3.15/esri/css/esri.css" /> <style> html, body { height: 100%; width: 100%; margin: 0; padding: 0; margin: 0; font-family: "Open Sans"; } #leftPane { width: 20%; margin: 0; border: none; } #map { padding: 0; } </style> <script src="https://js.arcgis.com/3.15/"></script> <script> require([ "dojo/ready", "dojo/on", "dojo/_base/lang", 'esri/tasks/RelationshipQuery', "dojo/dom", "dijit/registry", "dojo/dom-construct", "dojo/parser", "esri/map", "esri/arcgis/utils", "esri/domUtils", "esri/dijit/Popup", "esri/dijit/PopupTemplate", "dijit/layout/BorderContainer", "dijit/layout/ContentPane" ], function ( ready, on, lang, RelationshipQuery, dom, registry, domConstruct, parser, Map, arcgisUtils, domUtils, Popup, PopupTemplate, BorderContainer, ContentPane ) { ready(function () { parser.parse(); //Create a map based on an ArcGIS Online web map id arcgisUtils.createMap("ba61bf1495494336ba347b3286389cd8", "map").then(function (response) { window.map = response.map; this.selectedLayer = map.getLayer(response.itemInfo.itemData.operationalLayers[0].id); this.data = response.itemInfo.itemData.tables[0]; //set the popup's popupWindow property to false. This prevents the popup from displaying map.infoWindow.set("popupWinow", false); initializeSidebar(window.map); }, function (error) { console.log("Map creation failed: ", dojo.toJson(error)); }); function initializeSidebar(map) { var popup = map.infoWindow; //when the selection changes update the side panel to display the popup info for the //currently selected feature. on(popup, "selection-change", function () { displayPopupContent(popup.getSelectedFeature()); }); //when the selection is cleared remove the popup content from the side panel. on(popup, "clear-features", function () { dom.byId("featureCount").innerHTML = "Click to select feature(s)"; registry.byId("leftPane").set("content", ""); domUtils.hide(dom.byId("pager")); }); //When features are associated with the map's info window update the sidebar with the new content. on(popup, "set-features", function () { displayPopupContent(popup.getSelectedFeature()); dom.byId("featureCount").innerHTML = popup.features.length + " feature(s) selected"; //enable navigation if more than one feature is selected popup.features.length > 1 ? domUtils.show(dom.byId("pager")) : domUtils.hide(dom.byId("pager")); }); } function displayPopupContent(feature) { if (feature) { var updateQuery = new RelationshipQuery(); updateQuery.objectIds = [feature.attributes[this.selectedLayer.objectIdField]]; updateQuery.returnGeometry = true; updateQuery.outFields = ["*"]; updateQuery.relationshipId = this.selectedLayer.relationships[0].id; this.selectedLayer.queryRelatedFeatures(updateQuery, lang.hitch(this, function (results) { //If related record found, then set infotemplate of related table if (results[feature.attributes[this.selectedLayer.objectIdField]]) { results[feature.attributes[this.selectedLayer.objectIdField]].features[0].setInfoTemplate(new PopupTemplate(this.data.popupInfo)); //UnComment the following two lines to see proper result //var newLayer = new FeatureLayer(this.data.url); //results[feature.attributes[this.selectedLayer.objectIdField]].features[0]._layer = newLayer; setTimeout(function () { //get content of features and set it to left panel after specified time var content = results[feature.attributes[this.selectedLayer.objectIdField]].features[0].getContent(); registry.byId("leftPane").set("content", content); }, 500); } else { registry.byId("leftPane").set("content", "No Features Found"); } })); } } }); }); </script> </head> <body class="claro"> <div id="mainWindow" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline',gutters:false" style="width:100%; height:100%;"> <div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="gutters:false" region="left" style="width: 40%;height:100%;"> <div id="leftPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div> <div id="header" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'"> <div id="featureCount" style="margin-bottom:5px;">Click to select feature(s)</div> </div> </div> <div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div> </div> </body> </html>
Hi - just an fyi. I was on the phone with Esri for quite a bit this morning working with their developer support staff. Long story short, even though the documentation for AppBuilder says that it can support related tables within their Query widget, it can not. It's a known bug and has 2 enhancements logged in. I'll try using this code as a starting point as well.
BUG-000087466 : Attribute Widget does not display the correct table name in Web App Builder for ArcGIS when clicking on 'Show Related Records'
ENH-000091041
Preeti Gupta (08:57:48):
Allow Web Map's pop-up configuration for the related table to be carried over to the Web AppBuilder app.
ENH-000082871
Provide the ability to Query Related Records in ArcGIS Online hosted application templates and Web AppBuilder, as it is available through pop-up configuration in the Map Viewer
Thank you. I will use this as a starting point.