Select to view content in your preferred language

Questions about Robert Scheitlin's Identify Widget

2398
15
Jump to solution
09-17-2018 06:07 AM
LarryCosgrove
New Contributor III

First let me say that I am totally new to the Esri Web AppBuilder world and widgets but I find it fascinating and I am looking forward to learning more. Please forgive me for any awkward phrasing or incorrect terminology.

Let me also say that I am very impressed with Robert Scheitlin, GISP and his awesome Widgets. I am especially very keen on his Identify Widget. I am hoping to be able to make a few modifications that will help make it a very useful tool for me.

I hope to use the widget by being able to select a point on the map and having the widget display all of the Administrative Polygons the point is contained in. The polygons are simple: State, County, Township, City, Village, etc.. And the widget does exactly that out of the box.

That said, here are a few questions which I hope some kind developer's could assist me with:

  1. I was hoping that I could control the order in which the Admin Polygons are displayed in the results. However, no matter what I attempt (using the Layer Name Up/Down arrows in the widget configuration or manually editing the order in the config_Identify.json file), the results seem to display in whatever order they want. Is this the way it is or am I overlooking something? I have attached an example showing the results and the Layer Names in the configuration.
  2. In addition to displaying the Admin Polygons in the Results tab, it would also be helpful (at least to me) to also display the actual Longitude-Latitude value as the first entry in the Results tab. Has anyone already done this? And which files (json, js, html, config) would changes need to be made in order to do this? I have attached an example of what I would like to see.
  3. It would also be very nice to be able to have a "Copy and Paste" button, link, etc. included on the Results tab which would copy the text Results as a comma or tab-delimited file so that they could be pasted in an Excel file, Notepad, or Email. Has anyone made that type of change to the Identify Widget?

I would really appreciate any help or any links which might help me understand what I am doing wrong (#1) or how I might be able to implement (#'s 2 and 3).

Thanks

0 Kudos
15 Replies
LarryCosgrove
New Contributor III

Hi Robert,

Thank you for your patience with me. I am a novice at this but eager to learn.

Apparently, I just don't know how to properly create a Red StickPin Marker.

I have provided to screenshots showing the two different results I keep going back and forth with, and a screenshot of the two different blocks of code used to produce their corresponding results.

So Case 1 works repeatedly and wonderfully without errors to the console. The one thing not working is the display of the Red StickPin.

Case 2 kind of works. The Red StickPin can be repeatedly located. But I get the Console Error shown above each time I place a User Selected Point onto the map. I only see the User Selected Point Long-Lat in the Results, the progress strip moves constantly.

Here is that same block of code with the two cases defined at the bottom. (Case 1 is commented so Case 2 could be executed.)

So I think that my error is that I don't really understand how to properly construct the code to place the Red StickPin. I have looked on the internet and have stumbled upon and attempted to use some examples but there appears to be a half dozen different ways to accomplish the same thing.

Thanks for any help you can afford to me.

larry

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Larry,

   OK. Case one is the closest to what you need. The issue you have there is you create the graphic but you never define the geometry of the graphic. Also I have code to clear the graphics layer after the identify tasks are back from the server so where I am adding the user selected point now will get cleared when the results come back. Here are the tested change that need to be made.

Widget.js (clear out the changes you made before and add lines 176 - 202.)

      identifyFeatures: function(geom){
        this.numServicesIdent = 0;
        this.identifyResultsArray = [];
        this.iResultLen = 0;
        this.resultFound = false;
        this.list.clear();
        this.tabContainer.selectTab(this.nls.resultslabel);
        html.setStyle(this.progressBar.domNode, 'display', 'block');
        html.setStyle(this.divResult, 'display', 'none');

        var layers = array.map(this.map.layerIds, lang.hitch(this, function (layerId) {
          return this.map.getLayer(layerId);
        }));
        var featureLayers = array.map(this.map.graphicsLayerIds, lang.hitch(this, function (layerId) {
          return this.map.getLayer(layerId);
        }));

        featureLayers = array.filter(featureLayers, lang.hitch(this, function (layer){
          if(layer.type && layer.type === 'Feature Layer'){
            // layer.setAutoGeneralize(false);
            if(!layer.url || layer.url === '' || !layer.hasOwnProperty('url')){
              return false;
            }
            if(this.config.layers.onlythese === true){
              if(this.isService2beIdentified(layer)){
                if(this.identifylayeroption === 'visible' || this.identifylayeroption === 'top'){
                  if(!layer.visible || !layer.isVisibleAtScale(this.map.getScale())){
                    return false;
                  }
                }
                if(layer.version >= 10){
                  if(layer.capabilities.indexOf('Query') === -1){
                    return false;
                  }
                }
                this.numServicesIdent++;
                return true;
              }
            }else{
              if(this.identifylayeroption === 'visible' || this.identifylayeroption === 'top'){
                if(!layer.visible || !layer.isVisibleAtScale(this.map.getScale())){
                  return false;
                }
              }
              if(layer.version >= 10){
                if(layer.capabilities.indexOf('Query') === -1){
                  return false;
                }
              }
              if(this.isLayerNameExcluded(layer.name)){
                return false;
              }
              if(this._isFeatureLayerExcluded(layer.url)){
                return false;
              }
              this.numServicesIdent++;
              return true;
            }
          }
        }));

        layers = array.filter(layers, lang.hitch(this, function (layer) {
          if(!layer.url || layer.url === '' || !layer.hasOwnProperty('url')){
            return false;
          }
          if(this.config.layers.onlythese === true){
            if(this.isService2beIdentified(layer)){
              if(this.identifylayeroption === 'visible' || this.identifylayeroption === 'top'){
                if(!layer.visible || !layer.isVisibleAtScale(this.map.getScale())){
                  return false;
                }
              }
              if(this.isWholeServiceExcluded(layer.url)){
                return false;
              }

              if(layer.version >= 10){
                if(layer.capabilities.indexOf('Query') === -1){
                  return false;
                }
              }
              this.numServicesIdent++;
              return true;
            }
          }else{
            if(this.identifylayeroption === 'visible' || this.identifylayeroption === 'top'){
              if(!layer.visible || !layer.isVisibleAtScale(this.map.getScale())){
                return false;
              }
            }
            if(this.isWholeServiceExcluded(layer.url)){
              return false;
            }
            if(layer.version >= 10){
              if(layer.capabilities.indexOf('Query') === -1){
                return false;
              }
            }
            this.numServicesIdent++;
            return true;
          }
        }));

        var tasks = array.map(layers, lang.hitch(this, function (layer) {
          return new IdentifyTask(layer.url);
        }));

        var tasks2 = array.map(featureLayers, lang.hitch(this, function (layer) {
          return new QueryTask(layer.url);
        }));

        var FeatLyrNames = array.map(featureLayers, lang.hitch(this, function (layer) {
          return layer.name;
        }));

        var FeatLyrIds = array.map(featureLayers, lang.hitch(this, function (layer) {
          return layer.id;
        }));

        var LyrIds = array.map(layers, lang.hitch(this, function (layer) {
          return layer.id;
        }));

        var params = this.createIdentifyParams(layers, geom);
        var params2 = this.createQueryParams(featureLayers, geom);

        var promises = [];
        var promises2 = [];

        var fTasks = [], fLyrIds = [], fParams = [];
        for (var i = 0 ; i < tasks.length; i++) {
          if((params[i].layerIds && params[i].layerIds.length > 0) || this.identifylayeroption === "all"){
            promises.push(tasks[i].execute(params[i]));
            fTasks.push(tasks[i]);
            fLyrIds.push(LyrIds[i]);
            fParams.push(params[i]);
          }
        }

        for (i = 0; i < tasks2.length; i++) {
          promises2.push(tasks2[i].execute(params2[i]));
        }

        var iPromises = new all(promises);
        var qPromises = new all(promises2);
        iPromises.then(lang.hitch(this, function (r) {
          if(this.returngeometryforzoom){
            this.graphicsLayer.clear();
          }
          this.showIdentifyResults(r, fTasks, fLyrIds);
        }), lang.hitch(this, function (err){
          console.info(err);
        }));

        qPromises.then(lang.hitch(this, function (r) {
          if(this.returngeometryforzoom){
            this.graphicsLayer.clear();
          }
          this.showQueryResults(r, tasks2, FeatLyrNames, FeatLyrIds);
        }), lang.hitch(this, function (err){
          console.info(err);
        }));

        var tPromises = [iPromises, qPromises];

        var allPromises = new all(tPromises);
        allPromises.then(lang.hitch(this, function (r) {
          if (this.iResultLen === 0) {
            this.divResultMessage.textContent = this.nls.noresultsfoundlabel;
          } else {
            this.divResultMessage.textContent = this.nls.resultsfoundlabel + ' ' + this.iResultLen;
          }
          this.tabContainer.selectTab(this.nls.resultslabel);
          html.setStyle(this.progressBar.domNode, 'display', 'none');
          html.setStyle(this.divResult, 'display', 'block');
          if(geom.type === 'point'){
            var idResult = {};
            var rsltContent = '';
            idResult.icon = this.folderUrl + 'images/i_info.png';
            idResult.title = "User Selected Point";
            var value = this._formatNumber(geom.getLongitude(), 4, null, null) + ", " + this._formatNumber(geom.getLatitude(), 4, null, null);
            rsltContent = this.resultFormatString.replace('[attribname]', 'Longitude-Latitude').replace('[attribvalue]', value);
            if(rsltContent.lastIndexOf('<br>') === (rsltContent.length - 4)){
              idResult.rsltcontent = rsltContent.substr(0, rsltContent.length - 4);
            }else{
              idResult.rsltcontent = rsltContent;
            }
            idResult.zoom2msg = '';
            idResult.removeResultMsg = '';
            idResult.sym = this.resultSym;
            idResult.geometry = this.identifyGeom;
            idResult.point = this.identifyGeom;
            var iGra = new Graphic(this.identifyGeom, this.identMarkerSymbol);
            if(this.returngeometryforzoom){
              this.graphicsLayer.add(iGra);
            }
            idResult.id = 'id_' + this.gid;
            this.gid ++;
            idResult.forceScale = false;
            idResult.graphic = iGra;
            this.list.add(idResult, true);
          }
        }));
      },

In the List.js make these change to the add function (lines 1 and 128 - 132):

      add: function(item, first) {
        if (arguments.length === 0) {
          return;
        }
        this.items.push(item);
        var div = domConstruct.create('div');
        domAttr.set(div, 'id', this.id.toLowerCase()+item.id);
        domAttr.set(div, 'title', item.zoom2msg);

        var iconDiv = domConstruct.create('div');
        domAttr.set(iconDiv, 'id', this.id.toLowerCase()+item.id);
        domClass.add(iconDiv, 'iconDiv');
        domConstruct.place(iconDiv, div);

        var removeDiv = domConstruct.create('div');
        domConstruct.place(removeDiv, div);
        domClass.add(removeDiv, 'removediv');
        domAttr.set(removeDiv, 'id', this.id.toLowerCase()+item.id);

        var removeDivImg = domConstruct.create('div');
        domClass.add(removeDivImg, 'removedivImg');
        domConstruct.place(removeDivImg, removeDiv);
        domAttr.set(removeDivImg, 'id', this.id.toLowerCase()+item.id);
        domAttr.set(removeDivImg, 'title', item.removeResultMsg);
        this.own(on(removeDivImg, 'click', lang.hitch(this, this._onRemove)));

        var rTitle = domConstruct.create('p');
        domAttr.set(rTitle, 'id', this.id.toLowerCase()+item.id);
        domClass.add(rTitle, 'title');
        rTitle.textContent = rTitle.innerText = item.title;
        domConstruct.place(rTitle, div);
        if(item.alt){
          domClass.add(div, this._itemAltCSS);
        }else{
          domClass.add(div, this._itemCSS);
        }
        if(this._wrapResults){
          domClass.add(div, "result-wrap");
        }

        var attArr = item.rsltcontent.split('<br>');
        var attValArr, tHasColor, bIndex, eIndex, tColor, vHasColor, vColor;
        var label, attTitle, attVal;
        var arrayLength = attArr.length;
        for (var i = 0; i < arrayLength; i++) {
          attValArr = attArr[i].split(': ');
          attTitle = domConstruct.create('font');
          domAttr.set(attTitle, 'id', this.id.toLowerCase()+item.id);
          if(attValArr[0].toLowerCase().indexOf('<em>') > -1){
            domStyle.set(attTitle, 'font-style', 'italic');
          }
          if(attValArr[0].toLowerCase().indexOf('<strong>') > -1){
            domStyle.set(attTitle, 'font-weight', 'bold');
          }
          if(attValArr[0].toLowerCase().indexOf('<u>') > -1){
            domStyle.set(attTitle, 'text-decoration', 'underline');
          }
          tHasColor = (attValArr[0].toLowerCase().indexOf("<font color='") > -1)?true:false;
          if(tHasColor){
            bIndex = attValArr[0].toLowerCase().indexOf("<font color='") + 13;
            eIndex = attValArr[0].toLowerCase().indexOf("'>", bIndex);
            tColor = attValArr[0].substr(bIndex, eIndex - bIndex);
            domStyle.set(attTitle, 'color', tColor);
          }

          attTitle.textContent = attTitle.innerText = attValArr[0].replace(/<[\/]{0,1}(em|EM|strong|STRONG|font|FONT|u|U)[^><]*>/g, "") + ": ";
          label = domConstruct.create('p');
          domAttr.set(label, 'id', this.id.toLowerCase()+item.id);
          domClass.add(label, 'label');
          attVal = domConstruct.create('font');

          if(attValArr[1].toLowerCase().indexOf('<em>') > -1){
            domStyle.set(attVal, 'font-style', 'italic');
          }
          if(attValArr[1].toLowerCase().indexOf('<strong>') > -1){
            domStyle.set(attVal, 'font-weight', 'bold');
          }
          if(attValArr[1].toLowerCase().indexOf('<u>') > -1){
            domStyle.set(attVal, 'text-decoration', 'underline');
          }
          vHasColor = (attValArr[1].toLowerCase().indexOf("<font color='") > -1)?true:false;
          if(vHasColor){
            bIndex = attValArr[1].toLowerCase().indexOf("<font color='") + 13;
            eIndex = attValArr[1].toLowerCase().indexOf("'>", bIndex);
            vColor = attValArr[1].substr(bIndex, eIndex - bIndex);
            domStyle.set(attVal, 'color', vColor);
          }

          if (attValArr[1] === 'null') {
            attVal.textContent = attVal.innerText = ": ";
            domConstruct.place(attTitle, label);
            domConstruct.place(attVal, label);
          } else {
            var innerCont = domConstruct.toDom(attValArr[1].replace(/<[\/]{0,1}(em|EM|strong|STRONG|font|FONT|u|U)[^><]*>/g, ""));
            domConstruct.place(attTitle, label);
            domConstruct.place(innerCont, label);
          }
          domConstruct.place(label, div);
        }
        if(document.all && !document.addEventListener){
          //do nothing because it is IE8
          //And I can not produce swatches in IE8
        }else{
          var mySurface = gfx.createSurface(iconDiv, 40, 40);
          var descriptors = jsonUtils.getShapeDescriptors(item.sym);
          if(descriptors.defaultShape){
            var shape = mySurface.createShape(descriptors.defaultShape).setFill(descriptors.fill).setStroke(descriptors.stroke);
            shape.applyTransform({ dx: 20, dy: 20 });
          }
        }
        if(item.links && item.links.length > 0){
          var linksDiv = domConstruct.create("div");
          domConstruct.place(linksDiv, div);
          domClass.add(linksDiv, 'linksdiv');
        }
        //console.info(item.links);
        array.forEach(item.links, function(link){
          if(link.popuptype === "text"){
            var linkText = domConstruct.toDom("<p><a href='" + link.link + "' target='_blank' title='" + link.alias + "'>" + link.alias + "</a></p>");
            domConstruct.place(linkText, linksDiv, 'before');
            domClass.add(linkText, 'labellink');
          }else{
            var linkImg = domConstruct.toDom("<a href='" + link.link + "' target='_blank' title='" + link.alias + "'><img src='" + link.icon + "' alt='" + link.alias + "' border='0' width='20px' height='20px' style='vertical-align: middle;'></a>");
            domConstruct.place(linkImg, linksDiv);
            domClass.add(linkImg, 'linkIcon');
          }
        });
        if(first){
          domConstruct.place(div, this._listContainer, 'first');
        }else{
          domConstruct.place(div, this._listContainer);
        }
      },
LarryCosgrove
New Contributor III

Robert,

WOW!

I am so sorry that this required so much work for you. I thought it was just a simple drop of a few lines of code to place the pin. But the more I looked at it, the more I began to think that something was interfering with displaying the entire Results. You must have figured that out.

Everything works perfectly!

I apologize for taking so much of your time. You do amazing work and I have learned a lot from reviewing your widgets.

Please don't hate me.

Thanks so much,

larry

0 Kudos
LarryCosgrove
New Contributor III

Hi Robert,

I thought I would reply to this thread since it relates to the changes you have been gracious enough to provide to me.

Attached below is my version of your Identify widget with some changes I have made.

My last question(s) would be the best method to use within the Identify widget to allow the user to zoom into the Long-Lat location of the User Selected Point and within which block of code to place it. My thinking is that I could try to make changes to the area around line 490 in the Widget.js in which to pass the Long-Lat and then zoom to the location. But I wanted to stay as consistent as possible with your coding practices. It appears that the for all of the polygons which are displayed in the Results, their ID's are being stored and then their geometries being used to get the scale info, centered point within the polygon, and extent. I don't believe that this can be done with the Red Stick Pin graphic.

larry

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Larry,

   Here is the change (13 & 14):

          if(geom.type === 'point'){
            var idResult = {};
            var rsltContent = '';
            idResult.icon = this.folderUrl + 'images/i_info.png';
            idResult.title = "User Selected Point";
            var value = this._formatNumber(geom.getLongitude(), 4, null, null) + ", " + this._formatNumber(geom.getLatitude(), 4, null, null);
            rsltContent = this.resultFormatString.replace('[attribname]', 'Longitude-Latitude').replace('[attribvalue]', value);
            if(rsltContent.lastIndexOf('<br>') === (rsltContent.length - 4)){
              idResult.rsltcontent = rsltContent.substr(0, rsltContent.length - 4);
            }else{
              idResult.rsltcontent = rsltContent;
            }
            idResult.zoomScale = this.config.defaultzoomscale;
            idResult.zoom2msg = this.nls.zoom2message;
            idResult.removeResultMsg = '';
            idResult.sym = this.resultSym;
            idResult.geometry = this.identifyGeom;
            idResult.point = this.identifyGeom;
            var iGra = new Graphic(this.identifyGeom, this.identMarkerSymbol);
            if(this.returngeometryforzoom){
              this.graphicsLayer.add(iGra);
            }
            idResult.id = 'id_' + this.gid;
            this.gid ++;
            idResult.forceScale = false;
            idResult.graphic = iGra;
            this.list.add(idResult, true);
          }
LarryCosgrove
New Contributor III

Thank you, Robert!

I did come up with a workaround this morning but since you are so much more intimate with the inner workings of your code, your solution was a lot more elegant than mine. I have implemented your changes and of course, everything works as expected.

Again, much thanks.

larry

0 Kudos