Modify a webmap's InfoWindow with javascript in WAB

2688
12
Jump to solution
08-05-2020 07:36 AM
DávidGregor
New Contributor II

I made a custom popup for a specific layer. But my method is really not good for Web Appbuilder/WebMap environment.

Section from the customPopup widget:

      map = new Map("map", {
        infoWindow: infoWindow,
      });
      //create a popup to replace the map's info window
      var infoWindow = new InfoWindow({
        domNode: domConstruct.create("div"nulldom.byId("map")),
      });

      var popupTemplate = new InfoTemplate();
      popupTemplate.setContent(_getTextContent);
      var featureLayer = new FeatureLayer(substationURL, {
        mode: FeatureLayer.MODE_SNAPSHOT,
        infoTemplate: popupTemplate,
        outFields: ["*"],
      });

      this.map.addLayer(featureLayer);
      
  featureLayer.on('load'lang.hitch(thisfunction() {
          console.log("load");
          LayerInfos.getInstance(this.mapthis.map.itemInfo).then(lang.hitch(thisfunction(layerInfos) {
            var featureLayerInfo = layerInfos.getLayerInfoById(featureLayer.id);
            featureLayerInfo.title = 'Title';
            }));

This way, i have to remove the layer from the webmap to avoid duplication. 

I would rather modify programmatically the original layer's infoWindow. But i cannot find any documentation for this.

How can i reference existing objects? Every tutorial or sample creates new ones...

I tought something like this will work:

      this.layerStructure = LayerStructure.getInstance();
      var featureLayer = this.layerStructure.getNodeById(subLayerID);
      featureLayer.infoWindow = popupTemplate
0 Kudos
1 Solution

Accepted Solutions
CarlosNantes
New Contributor III

Based on your json output, and knowing it is a ArcGISDynamicMapServiceLayer, the snippet should work if you try:

var layerId = 'alallomas_9075';  

var operationalLayer = getWebmapOperationalLayerById(layerId);
operationalLayer.getLayerObject().then(function(layerObject){

   var title = 'Popup title';
   var content = 'Custom description. You can use HTML here. <br> And access attribute value like this ${SOME_ATRIBUTE}';

    var sublayerId = 0;

   if(!layerObject.infotemplates){

        layerObject.infotemplates = {};

   }
    layerObject.infotemplates[sublayerId]= {

          infoTemplate: new InfoTemplate(title, content);

    });

})

In ArcGISDynamicMapServiceLayer, infotemplates are stored in a different way.

The id alallomas_9075_0 means: alallomas is the mapserver name, 9075 is (probably) a random number and 0 is the sublayerId. This is not documented, by the way....

View solution in original post

12 Replies
RobertScheitlin__GISP
MVP Emeritus

David,

  LayerStructure getNodeById is the right path but once you have the node you need to use the getLayerObject() method on the node before you have an actual FeatureLayer.

 this.layerStructure = LayerStructure.getInstance();
 var featureLayer = this.layerStructure.getNodeById(subLayerID).getLayerObject();
 featureLayer.infoWindow = popupTemplate‍‍‍
0 Kudos
DávidGregor
New Contributor II

Robert,

Probably i should quit my job, because i'm stupid, i tried, googled, read for hours without success,

I don't return my feature layer, maybe that's my problem. Please, show my more info. 

featureLayer's console log:

"Error at Object._getLayerObject (/jimu.js/LayerInfos/LayerInfoForDefaultService.js?wab_dv=2.15:187:17) at Object.getLayerObject (/jimu.js/LayerInfos/LayerInfoForDefaultService.js?wab_dv=2.15:208:19) at Object.getLayerObject (/jimu.js/LayerNode.js?wab_dv=2.15:200:30) at Object.startup (/widgets/CustomPopup/Widget.js?wab_dv=2.15:178:40) at Object.advice (https://js.arcgis.com/3.31/init.js:121:101) at Object.c [as startup] (https://js.arcgis.com/3.31/init.js:120:393) at Object.openWidget (/jimu.js/WidgetManager.js?wab_dv=2.15:540:18) at Object.<anonymous> (/jimu.js/layoutManagers/BaseLayoutManager.js?wab_dv=2.15:208:32) at https://js.arcgis.com/3.31/init.js:64:337 at m (https://js.arcgis.com/3.31/init.js:108:248)"

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

David,

   It sounds like the "subLayerID" you are searching for is returning null. Have you done a simple test like this:

console.log(this.layerStructure.getNodeById(subLayerID));

If you are not getting a null from getNodeById and you are actually getting the node object back then you can try this code to get to the layer object from the node:

var foundLayer = this.layerStructure.getNodeById(subLayerID);
// if(foundLayer !== 'undefined') {
if(foundLayer) {
  var featureLayer = foundLayer._layerInfo.layerObject;
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
DávidGregor
New Contributor II

Sorry for the delay, i just finished work, when you answered.

I get back a layernode:

  1. id: "alallomas_9075_0"
  2. map: {_plugins: {…}, _internalLayerIds: Array(1), _layers: Array(0), _layerDivs: Array(0), _basemapPending: false, …}
  3. subId: 0
  4. title: "Alállomás"
  5. _layerInfo: {originOperLayer: {…}, layerObject: {…}, map: {…}, title: "Alállomás", id: "alallomas_9075_0", …}
  6. __proto__: Object

and now an object also as the featurelayer. but its not so right.

JSON.stringify(featureLayer)  // {"url":"https:/webserver.local/arcgis/rest/services/alallomas/MapServer/0","empty":true}

I have no clue why it is empty.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

David,

   I almost seems like you are trying to a featurelayer object from a sublayer of a ArcGISDynamicMapServiceLayer. If that is the case then that is the issue.

DávidGregor
New Contributor II

Totally right! Are there any methods to deal with  them?  Sorry, that i didn't know that this is a big difference. i tought a sublayer is a featurelayer. Services served from arcmap mxd-s contain featurelayers..

0 Kudos
CarlosNantes
New Contributor III

Time is necessary to master any tecnology, frustration is part of the process. I have struggled with this same problem a while ago.  Here is a snippet you can copy and paste in google chrome developer console to see it working. The web appbuilder application must be opened in the browser tab for you to try this.

I think this part of the api is really missing some docs. LayerStructure module uses LayerInfos behind the scenes. The sample code uses LayerInfos module directly.


var LayerInfos =  require('jimu/LayerInfos/LayerInfos');
var InfoTemplate =  require('esri/InfoTemplate');

function getWebmapOperationalLayerById (layerId) {
    var instance = LayerInfos.getInstanceSync();
    var layerFound = null;
    instance.traversalLayerInfosOfWebmap(function (aLayer) {
        if (aLayer.id === layerId) {
            layerFound = aLayer;
            return//get out of traversalLayerInfosOfWebmap()
        }
    });
    return layerFound;
}

function modifyInfoTemplatelayerObject) {
    var title = 'Popup title';
    var content = 'Custom description. You can use HTML here. <br> And access attribute value like this ${SOME_ATRIBUTE}'
    layerObject.infoTemplate = new InfoTemplate(titlecontent);
}

var layerId = 'YOUR_LAYER_ID_HERE'
var operationalLayer = getWebmapOperationalLayerById(layerId);
operationalLayer.getLayerObject().then(modifyInfoTemplate);   

It is important to use operationalLayer.getLayerObject() method (instead of accessing directly operationalLayer.layerObject), because sometimes layerObject is not loaded and will be empty. getLayerObject() will assure the object is loaded before you modify infotemplate.

To find a layerId you can use _viewerMap._layers in chrome developer console to see what's in there.

DávidGregor
New Contributor II

Thanks for the snippet! 

I got back a circular object, but after getLayerObject method, it became the same empty promise.

WAB env. is not for the beginners  but i won't give up! 

0 Kudos
CarlosNantes
New Contributor III

Based on your json output, and knowing it is a ArcGISDynamicMapServiceLayer, the snippet should work if you try:

var layerId = 'alallomas_9075';  

var operationalLayer = getWebmapOperationalLayerById(layerId);
operationalLayer.getLayerObject().then(function(layerObject){

   var title = 'Popup title';
   var content = 'Custom description. You can use HTML here. <br> And access attribute value like this ${SOME_ATRIBUTE}';

    var sublayerId = 0;

   if(!layerObject.infotemplates){

        layerObject.infotemplates = {};

   }
    layerObject.infotemplates[sublayerId]= {

          infoTemplate: new InfoTemplate(title, content);

    });

})

In ArcGISDynamicMapServiceLayer, infotemplates are stored in a different way.

The id alallomas_9075_0 means: alallomas is the mapserver name, 9075 is (probably) a random number and 0 is the sublayerId. This is not documented, by the way....