DevEdition Wab - Search Widget JS Highlight Symbol: Changes from 2.7 through 2.11

4568
24
Jump to solution
11-29-2017 02:00 PM
DavidColey
Frequent Contributor

Hi all - this is in reference to the earlier post dealing with the same issue at 1.3 and 2.3:

Web AppBuilder 1.2 Search/Geocoder widget color/style question 

but thought I'd start a new thread because the changes in the Search widget's Widget.js code at 2.6 have rendered the earlier fix (that worked up through 2.5) when starting a new app in the 2.6 Developer edition

As in earlier 2.x versions, to change the default highlight symbol I add in the jsonUtils to the define function and alias:

define([
 'dojo/_base/declare',
 'dojo/_base/lang',
 'dojo/_base/array',
 'dojo/_base/html',
 'dojo/when',
 'dojo/on',
 'dojo/aspect',
 'dojo/query',
 'dojo/keys',
 'dojo/Deferred',
 'dojo/promise/all',
 'jimu/BaseWidget',
 'jimu/LayerInfos/LayerInfos',
 'jimu/utils',
 'esri/dijit/Search',
 'esri/tasks/locator',
 'esri/layers/FeatureLayer',
 'esri/InfoTemplate',
 'esri/lang',
 './utils',
 'esri/symbols/jsonUtils', //for highlight change
 'dojo/NodeList-dom'
 ],
 function(declare, lang, array, html, when, on, aspect, query, keys, Deferred, all,
 BaseWidget, LayerInfos, jimuUtils, Search, Locator,
 FeatureLayer, InfoTemplate, esriLang, utils, jsonUtils)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

On about line 330 in the code, I add the highlight symbol property to the convertedSource var inside the _convertConfig function:

var convertedSource = {
 featureLayer: flayer,
 outFields: ["*"],
 searchFields: fNames,
 displayField: source.displayField || "",
 exactMatch: !!source.exactMatch,
 name: jimuUtils.stripHTML(source.name || ""),
 placeholder: jimuUtils.stripHTML(source.placeholder || ""),
 maxSuggestions: source.maxSuggestions || 6,
 maxResults: source.maxResults || 6,
 zoomScale: source.zoomScale || 50000,
 infoTemplate: template,
 useMapExtent: !!source.searchInCurrentMapExtent,
 _featureLayerId: source.layerId,
 highlightSymbol: jsonUtils.fromJson(source.highlightSymbol) //to add highlight symbol from json
 };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

the highlightSymbol is set for each of the layers in the config.json:

"highlightSymbol": {
 "color": [100,100,100,25],
    "outline": {
       "color": [102,0,204],
          "width": 5,"type": "esriSLS" , "style", "esriSLSSolid"
    },"type": "esriSFS" ,"style": "esriSFSSolid"}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

and returns my settings to me in the console.log, but still reverts to the default highlight color and thickness, regardless:

So what should be a thick purple outline comes back in the default setting.  I've gone through the code to try to find what would be preventing the earlier method from working but have not had success.  Here are the changes, the comments here are the esri developer's comments:

On about line 137, a new promise(?) and handler for the infoWindow is added, not present in earlier 2.x:

// attatch original feature layer's id.
 this.own(
 aspect.before(this.map.infoWindow, 'setFeatures', lang.hitch(this, '_attatchOriLayerId'))
 );
 // this.map.infoWindow has two different implementations (esri/dijit/Popup and esri/dijit/PopupMobile)
 // after screen size changed. map switch it automatically.
 // here make sure fun:setFeatures be binded
 this._mapInfoWindow_ = this.map.infoWindow;
 var _winResizeHandler = on(window, 'resize', lang.hitch(this, function() {
 if (this._mapInfoWindow_ !== this.map.infoWindow) {
 this.own(
 aspect.before(this.map.infoWindow, 'setFeatures', lang.hitch(this, '_attatchOriLayerId'))
 );
 _winResizeHandler.remove();
 }
 }));‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

at about line 182, a 'show,hide' on event that I previously used to persist a graphic on-screen after the infoWindow closes has been commented out (a separate behavior):

// this.own(
 // on(this.map.infoWindow, 'show,hide', lang.hitch(this, function() {
 // if (this.searchDijit &&
 // this.map.infoWindow.getSelectedFeature() ===
 // this.searchDijit.highlightGraphic) {
 // this.searchDijit.clearGraphics();
 // query('li', this.searchResultsNode).removeClass('result-item-selected');
 // }
 // }))
 // );‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The next changes begin on about line 677 as part of the _onSelectedSeachResult function:

// clear before select.
 this.searchDijit.clearGraphics();‍‍‍‍‍‍‍‍

Then more commented code as part of the _onSelectResult function at line 683:

_onSelectResult: function(e) {
 var result = e.result;
 if (!(result && result.name)) {
 return;
 }
 var dataSourceIndex = e.sourceIndex;
 var sourceResults = this.searchResults[dataSourceIndex];
 var dataIndex = 0;
 // var that = this;
// var getGraphics = function(layer, fid) {
 // var graphics = layer.graphics;
 // var gs = array.filter(graphics, function(g) {
 // return g.attributes[layer.objectIdField] === fid;
 // });
 // return gs;
 // };
 // var showPopupByFeatures = function(features) {
 // var location = null;
 // that.map.infoWindow.setFeatures(features);
 // if (features[0].geometry.type === "point") {
 // location = features[0].geometry;
 // } else {
 // location = features[0].geometry.getExtent().getCenter();
 // }
 // that.map.infoWindow.show(location, {
 // closetFirst: true
 // });
 // };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

and again beginning at line 733:

// var layer = this.map.getLayer(e.source._featureLayerId);
// if (layer && this.config.showInfoWindowOnSelect) {
 // var gs = getGraphics(layer, e.result.feature.__attributes[layer.objectIdField]);
 // if (gs.length > 0) {
 // showPopupByFeatures(gs);
 // } else {
 // var handle = on(layer, 'update-end', lang.hitch(this, function() {
 // if (this.domNode) {
 // var gs = getGraphics(layer, e.result.feature.__attributes[layer.objectIdField]);
 // if (gs.length > 0) {
 // showPopupByFeatures(gs);
 // }
 // }
// if (handle && handle.remove) {
 // handle.remove();
 // }
 // }));
 // this.own(handle);
 // }
 // }
 // publish select result to other widgets‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Finally, I believe this new code at line 760 may be where the highlightSymbol graphic may be NOT drawing, but I can't be certain:

// hide the graphic in map's default graphiclayer.
 var _searchGL = this.searchDijit.graphicsLayer || this.map.graphics;
 _searchGL.graphics.forEach(lang.hitch(this,function(item) {
 if (item && lang.getObject("_wabProperties.referToFeatureLayerId", false, item)) {
 // this.searchDijit.clearGraphics();
 _searchGL.remove(item);
 }
 }));
 },
_attatchOriLayerId: function(fs) {
 // Summary: attatchOriLayerId _attatch original featureLayer's ID.
 // Condition:
 // 1. Search dijit of JSAPI create new graphic and add it to map's default graphicslayer
 // if no graphicslayer configured, map contains two same graphic at the same time.
 // 2. Attach original flayer's id as a property to graphic(map's default featurelayer),
 // WAB can create related records with .
// fs is an array, it's item could be 'esri.Graphic' or 'dojo.deferred'
if (fs && fs.length && fs[0].declaredClass === "esri.Graphic" &&
 esriLang.isDefined(this._currentSelectSourceIdx)) {
 // iterator every item
 fs.forEach(lang.hitch(this, function(item) {
 // only type 'esri.Graphic'
 if (item.declaredClass === "esri.Graphic") {
 // original featurelayer id
 var _featureLayerId = this.searchDijit.sources[this._currentSelectSourceIdx]._featureLayerId;
 // get original featurelayer if exists.
 var layer = _featureLayerId && this.layerInfosObj.getLayerInfoById(_featureLayerId);
 // if original featurelayer added to map
 if (layer && this.config.showInfoWindowOnSelect) {
 // attatch original featurelayer's ID to this feature
 lang.setObject("_wabProperties.referToFeatureLayerId", _featureLayerId, item);
 }
 }
 }));
 }
 },‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

So if anyone has any suggestions as to where I can add/remove or otherwise comment code in order to be able to draw a custom highlight upon a result selection that would certainly help, because I just can't see it. 

As an fyi I did not see any other changes to any other js or json files contained with the Search.  The only changes appear to be in the Widget.js

Thanks,

David

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

David,

  OK, then here is the whole file with my changes for option 2:

_onSelectResult lines 763 - 769 are the important new changes for 2.6 (commenting these lines).

///////////////////////////////////////////////////////////////////////////
// Copyright © 2015 Esri. All Rights Reserved.
//
// Licensed under the Apache License Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///////////////////////////////////////////////////////////////////////////

define([
    'dojo/_base/declare',
    'dojo/_base/lang',
    'dojo/_base/array',
    'dojo/_base/html',
    'dojo/when',
    'dojo/on',
    'dojo/aspect',
    'dojo/query',
    'dojo/keys',
    'dojo/Deferred',
    'dojo/promise/all',
    'jimu/BaseWidget',
    'jimu/LayerInfos/LayerInfos',
    'jimu/utils',
    'esri/dijit/Search',
    'esri/tasks/locator',
    'esri/layers/FeatureLayer',
    'esri/InfoTemplate',
    'esri/lang',
    './utils',
    'esri/symbols/jsonUtils', //for highlight change
    'dojo/NodeList-dom'
  ],
  function(declare, lang, array, html, when, on, aspect, query, keys, Deferred, all,
    BaseWidget, LayerInfos, jimuUtils, Search, Locator,
    FeatureLayer, InfoTemplate, esriLang, utils, jsonUtils) {
    //To create a widget, you need to derive from BaseWidget.
    return declare([BaseWidget], {
      name: 'Search',
      baseClass: 'jimu-widget-search',
      searchDijit: null,
      searchResults: null,

      _startWidth: null,

      postCreate: function() {
        if (this.closeable || !this.isOnScreen) {
          html.addClass(this.searchNode, 'default-width-for-openAtStart');
        }

        this.listenWidgetIds.push('framework');
      },

      startup: function() {
        this.inherited(arguments);

        if (!(this.config && this.config.sources)) {
          this.config.sources = [];
        }

        LayerInfos.getInstance(this.map, this.map.itemInfo)
          .then(lang.hitch(this, function(layerInfosObj) {
            this.layerInfosObj = layerInfosObj;
            this.own(this.layerInfosObj.on(
            'layerInfosFilterChanged',
            lang.hitch(this, this.onLayerInfosFilterChanged)));

            utils.setMap(this.map);
            utils.setLayerInfosObj(this.layerInfosObj);
            utils.setAppConfig(this.appConfig);
            when(utils.getConfigInfo(this.config)).then(lang.hitch(this, function(config) {
              return all(this._convertConfig(config)).then(function(searchSouces) {
                return array.filter(searchSouces, function(source) {
                  return source;
                });
              });
            })).then(lang.hitch(this, function(searchSouces) {
              if (!this.domNode) {
                return;
              }

              this.searchDijit = new Search({
                activeSourceIndex: searchSouces.length === 1 ? 0 : 'all',
                allPlaceholder: jimuUtils.stripHTML(esriLang.isDefined(this.config.allPlaceholder) ?
                  this.config.allPlaceholder : ""),
                autoSelect: true,
                enableButtonMode: false,
                enableLabel: false,
                enableInfoWindow: true,
                enableHighlight: esriLang.isDefined(this.config.showInfoWindowOnSelect) ?
                  !!this.config.showInfoWindowOnSelect : true,
                showInfoWindowOnSelect: esriLang.isDefined(this.config.showInfoWindowOnSelect) ?
                  !!this.config.showInfoWindowOnSelect : true,
                map: this.map,
                sources: searchSouces,
                theme: 'arcgisSearch'
              });
              html.place(this.searchDijit.domNode, this.searchNode);
              this.searchDijit.startup();

              this._resetSearchDijitStyle();

              this.own(
                this.searchDijit.watch(
                  'activeSourceIndex',
                  lang.hitch(this, '_onSourceIndexChange')
                )
              );

              this.own(
                on(this.searchDijit.domNode, 'click', lang.hitch(this, '_onSearchDijitClick'))
              );
              this.own(on(this.searchDijit.inputNode, "keyup", lang.hitch(this, function(e) {
                if (e.keyCode !== keys.ENTER) {
                  this._onClearSearch();
                }
              })));
              this.own(
                aspect.before(this.searchDijit, 'select', lang.hitch(this, '_captureSelect'))
                );
              this.own(
                on(this.searchDijit, 'search-results', lang.hitch(this, '_onSearchResults'))
              );
              this.own(
                on(this.searchDijit, 'suggest-results', lang.hitch(this, '_onSuggestResults'))
              );
              this.own(
                on(this.searchDijit, 'select-result', lang.hitch(this, '_onSelectResult'))
              );
              // attatch original feature layer's id.
              this.own(
                aspect.before(this.map.infoWindow, 'setFeatures', lang.hitch(this, '_attatchOriLayerId'))
              );
              // this.map.infoWindow has two different implementations (esri/dijit/Popup and esri/dijit/PopupMobile)
              //  after screen size changed. map switch it automatically.
              // here make sure fun:setFeatures be binded
              this._mapInfoWindow_ = this.map.infoWindow;
              var _winResizeHandler = on(window, 'resize', lang.hitch(this, function() {
                if (this._mapInfoWindow_ !== this.map.infoWindow) {
                  this.own(
                    aspect.before(this.map.infoWindow, 'setFeatures', lang.hitch(this, '_attatchOriLayerId'))
                  );
                  _winResizeHandler.remove();
                }
              }));
              this.own(
                on(this.searchResultsNode, 'li:click', lang.hitch(this, '_onSelectSearchResult'))
              );
              this.own(on(
                this.searchResultsNode,
                '.show-all-results:click',
                lang.hitch(this, '_showResultMenu')
              ));
              this.own(
                on(window.document, 'click', lang.hitch(this, function(e) {
                  if (!html.isDescendant(e.target, this.searchResultsNode)) {
                    this._hideResultMenu();
                    this._resetSelectorPosition('.show-all-results');
                  }
                }))
              );
              this.own(
                on(this.searchDijit, 'clear-search', lang.hitch(this, '_onClearSearch'))
              );
              this.own(
                aspect.after(this.map.infoWindow, 'show', lang.hitch(this, function() {
                  if (this.searchDijit &&
                    this.map.infoWindow.getSelectedFeature() !==
                    this.searchDijit.highlightGraphic) {
                    //this.searchDijit.clearGraphics();
                    query('li', this.searchResultsNode).removeClass('result-item-selected');
                  }
                }))
              );
              // this.own(
              //   on(this.map.infoWindow, 'show,hide', lang.hitch(this, function() {
              //     if (this.searchDijit &&
              //       this.map.infoWindow.getSelectedFeature() ===
              //       this.searchDijit.highlightGraphic) {
              //       this.searchDijit.clearGraphics();
              //       query('li', this.searchResultsNode).removeClass('result-item-selected');
              //     }
              //   }))
              // );

              this.fetchData('framework');
            }));
          }));
      },

      onReceiveData: function(name, widgetId, data) {
        if (name === 'framework' && widgetId === 'framework' && data && data.searchString) {
          this.searchDijit.set('value', data.searchString);
          this.searchDijit.search();
        }
      },

      setPosition: function(position) {
        this._resetSearchDijitStyle(position);
        this.inherited(arguments);
      },

      resize: function() {
        this._resetSearchDijitStyle();
      },

      onLayerInfosFilterChanged: function(changedLayerInfos) {
        array.some(changedLayerInfos, lang.hitch(this, function(info) {
          if (this.searchDijit && this.searchDijit.sources && this.searchDijit.sources.length > 0) {
            array.forEach(this.searchDijit.sources, function(s) {
              if (s._featureLayerId === info.id) {
                s.featureLayer.setDefinitionExpression(info.getFilter());
              }
            });
          }
        }));
      },

      _resetSearchDijitStyle: function() {
        html.removeClass(this.domNode, 'use-absolute');
        if (this.searchDijit && this.searchDijit.domNode) {
          html.setStyle(this.searchDijit.domNode, 'width', 'auto');
        }

        setTimeout(lang.hitch(this, function() {
          if (this.searchDijit && this.searchDijit.domNode) {
            var box = {
              w: !window.appInfo.isRunInMobile ? 274 : // original width of search dijit
                parseInt(html.getComputedStyle(this.domNode).width, 10)
            };
            var sourcesBox = html.getMarginBox(this.searchDijit.sourcesBtnNode);
            var submitBox = html.getMarginBox(this.searchDijit.submitNode);
            var style = null;
            if (box.w) {
              html.setStyle(this.searchDijit.domNode, 'width', box.w + 'px');
              html.addClass(this.domNode, 'use-absolute');

              if (isFinite(sourcesBox.w) && isFinite(submitBox.w)) {
                if (window.isRTL) {
                  style = {
                    left: submitBox.w + 'px',
                    right: sourcesBox.w + 'px'
                  };
                } else {
                  style = {
                    left: sourcesBox.w + 'px',
                    right: submitBox.w + 'px'
                  };
                }
                var inputGroup = query('.searchInputGroup', this.searchDijit.domNode)[0];

                if (inputGroup) {
                  html.setStyle(inputGroup, style);
                  var groupBox = html.getMarginBox(inputGroup);
                  var extents = html.getPadBorderExtents(this.searchDijit.inputNode);
                  html.setStyle(this.searchDijit.inputNode, 'width', groupBox.w - extents.w + 'px');
                }
              }
            }
          }
        }), 50);
      },

      _convertConfig: function(config) {
        var sourceDefs = array.map(config.sources, lang.hitch(this, function(source) {
          var def = new Deferred();
          if (source && source.url && source.type === 'locator') {
            var _source = {
              locator: new Locator(source.url || ""),
              outFields: ["*"],
              singleLineFieldName: source.singleLineFieldName || "",
              name: jimuUtils.stripHTML(source.name || ""),
              placeholder: jimuUtils.stripHTML(source.placeholder || ""),
              countryCode: source.countryCode || "",
              maxSuggestions: source.maxSuggestions,
              maxResults: source.maxResults || 6,
              zoomScale: source.zoomScale || 50000,
              useMapExtent: !!source.searchInCurrentMapExtent
            };

            if (source.enableLocalSearch) {
              _source.localSearchOptions = {
                minScale: source.localSearchMinScale,
                distance: source.localSearchDistance
              };
            }

            def.resolve(_source);
          } else if (source && source.url && source.type === 'query') {
            var searchLayer = new FeatureLayer(source.url || null, {
              outFields: ["*"]
            });

            this.own(on(searchLayer, 'load', lang.hitch(this, function(result) {
              var flayer = result.layer;
              var template = this._getInfoTemplate(flayer, source, source.displayField);
              var fNames = null;
              if (source.searchFields && source.searchFields.length > 0) {
                fNames = source.searchFields;
              } else {
                fNames = [];
                array.forEach(flayer.fields, function(field) {
                  if (field.type !== "esriFieldTypeOID" && field.name !== flayer.objectIdField &&
                    field.type !== "esriFieldTypeGeometry") {
                    fNames.push(field.name);
                  }
                });
              }
              var convertedSource = {
                featureLayer: flayer,
                outFields: ["*"],
                searchFields: fNames,
                displayField: source.displayField || "",
                exactMatch: !!source.exactMatch,
                name: jimuUtils.stripHTML(source.name || ""),
                placeholder: jimuUtils.stripHTML(source.placeholder || ""),
                maxSuggestions: source.maxSuggestions || 6,
                maxResults: source.maxResults || 6,
                zoomScale: source.zoomScale || 50000,
                infoTemplate: template,
                useMapExtent: !!source.searchInCurrentMapExtent,
                _featureLayerId: source.layerId
              };
              if(source.highlightSymbol){
                convertedSource.highlightSymbol = jsonUtils.fromJson(source.highlightSymbol);
                //this.map.infoWindow.fillSymbol = jsonUtils.fromJson(source.highlightSymbol);
              }
              if (!template) {
                delete convertedSource.infoTemplate;
              }
              if (convertedSource._featureLayerId) {
                var layerInfo = this.layerInfosObj
                  .getLayerInfoById(convertedSource._featureLayerId);
                flayer.setDefinitionExpression(layerInfo.getFilter());
              }
              def.resolve(convertedSource);
            })));

            this.own(on(searchLayer, 'error', function() {
              def.resolve(null);
            }));
          } else {
            def.resolve(null);
          }
          return def;
        }));

        return sourceDefs;
      },

      _getInfoTemplate: function(fLayer, source, displayField) {
        var layerInfo = this.layerInfosObj.getLayerInfoById(source.layerId);
        var template = layerInfo && layerInfo.getInfoTemplate();
        var validTemplate = layerInfo && template;

        if (layerInfo && !validTemplate) { // doesn't enabled pop-up
          return null;
        } else if (validTemplate) {
          // configured media or attachments
          return template;
        } else { // (added by user in setting) or (only configured fieldInfo)
          template = new InfoTemplate();
          template.setTitle(' ');
          template.setContent(
            lang.hitch(this, '_formatContent', source.name, fLayer, displayField)
          );

          return template;
        }
      },

      _getSourcePopupInfo: function(source) {
        if (source._featureLayerId) {
          var layerInfo = this.layerInfosObj.getLayerInfoById(source._featureLayerId);
          if (layerInfo) {
            return layerInfo.getPopupInfo();
          }
        }
        return null;
      },

      _captureSelect: function(e) {
        var sourceIndex = this.searchDijit.activeSourceIndex;
        if (sourceIndex === 'all') {
          sourceIndex = this._getSourceIndexOfResult(e);
        }
        if (isFinite(sourceIndex) && esriLang.isDefined(sourceIndex)) {
          // record current select source index, for FUN:_attatchOriLayerId.
          this._currentSelectSourceIdx = sourceIndex;
          var source = this.searchDijit.sources[sourceIndex];
          if (source && 'featureLayer' in source) {
            var popupInfo = this._getSourcePopupInfo(source);
            var notFormatted = (popupInfo && popupInfo.showAttachments) ||
              (popupInfo && popupInfo.description &&
              popupInfo.description.match(/http(s)?:\/\//)) ||
              (popupInfo && popupInfo.mediaInfos && popupInfo.mediaInfos.length > 0);

            // set a private property for select-result to get original feature from layer.
            if (!e.feature.__attributes) {
              e.feature.__attributes = e.feature.attributes;
            }

            if (!notFormatted) {
              var formatedAttrs = this._getFormatedAttrs(
                lang.clone(e.feature.attributes),
                source.featureLayer.fields,
                source.featureLayer.typeIdField,
                source.featureLayer.types,
                popupInfo
              );

              e.feature.attributes = formatedAttrs;
            }
          }
        }

        return [e];
      },

      _getSourceIndexOfResult: function(e) {
        if (this.searchResults){
          for (var i in this.searchResults) {
            var sourceResults = this.searchResults[i];
            var pos = array.indexOf(sourceResults, e);
            if (pos > -1) {
              return parseInt(i, 10);
            }
          }
        }

        return null;
      },

      _formatContent: function(title, fLayer, displayField, graphic) {
        var content = "";
        if (graphic && graphic.attributes && fLayer && fLayer.url) {
          var aliasAttrs = {};
          array.forEach(fLayer.fields, lang.hitch(this, function(field) {
            if (field.name in graphic.attributes){
              aliasAttrs[field.alias || field.name] = graphic.attributes[field.name];
            }
          }));
          var displayValue = graphic.attributes[displayField];
          content += '<div class="esriViewPopup">' +
            '<div class="mainSection">' +
            (esriLang.isDefined(displayValue) ?
              ('<div class="header">' + title + ': ' + displayValue + '</div>') : "") +
            '<div class="hzLine"></div>' +
            '<div>' +
            '<table class="attrTable" cellpading="0" cellspacing="0">' +
            '<tbody>';
          for (var p in aliasAttrs) {
            if (aliasAttrs.hasOwnProperty(p)) {
              content += '<tr valign="top">' +
                '<td class="attrName">' + p + '</td>' +
                '<td class="attrValue">' + aliasAttrs[p] + '</td>' +
                '</tr>';
            }
          }
          content += '</tbody>' +
            '</table>' +
            '</div>' +
            '<div class="break"></div>' +
            '</div>';
        }

        return content;
      },

      _getFormatedAttrs: function(attrs, fields, typeIdField, types, popupInfo) {
        function getFormatInfo(fieldName) {
          if (popupInfo && esriLang.isDefined(popupInfo.fieldInfos)) {
            for (var i = 0, len = popupInfo.fieldInfos.length; i < len; i++) {
              var f = popupInfo.fieldInfos[i];
              if (f.fieldName === fieldName) {
                return f.format;
              }
            }
          }

          return null;
        }

        var aliasAttrs = {};
        array.forEach(fields, lang.hitch(this, function(_field, i) {
          if (!attrs[_field.name]) {
            return;
          }
          var isCodeValue = !!(_field.domain && _field.domain.type === 'codedValue');
          var isDate = _field.type === "esriFieldTypeDate";
          var isTypeIdField = typeIdField && (_field.name === typeIdField);
          var fieldAlias = _field.name;

          if (fields[i].type === "esriFieldTypeDate") {
            aliasAttrs[fieldAlias] = jimuUtils.fieldFormatter.getFormattedDate(
              attrs[_field.name], getFormatInfo(_field.name)
              );
          } else if (fields[i].type === "esriFieldTypeDouble" ||
            fields[i].type === "esriFieldTypeSingle" ||
            fields[i].type === "esriFieldTypeInteger" ||
            fields[i].type === "esriFieldTypeSmallInteger") {
            aliasAttrs[fieldAlias] = jimuUtils.fieldFormatter.getFormattedNumber(
              attrs[_field.name], getFormatInfo(_field.name)
              );
          }

          if (isCodeValue) {
            aliasAttrs[fieldAlias] = jimuUtils.fieldFormatter.getCodedValue(
              _field.domain, attrs[_field.name]
              );
          } else if (isTypeIdField) {
            aliasAttrs[fieldAlias] = jimuUtils.fieldFormatter.getTypeName(
              attrs[_field.name], types
              );
          } else if (!isCodeValue && !isDate && !isTypeIdField) {
            // Not A Date, Domain or Type Field
            // Still need to check for codedType value
            aliasAttrs[fieldAlias] = fieldAlias in aliasAttrs ?
              aliasAttrs[fieldAlias] : attrs[_field.name];
            aliasAttrs[fieldAlias] = this.getCodeValueFromTypes(
              _field,
              typeIdField,
              types,
              attrs,
              aliasAttrs
            );
          }
        }));
        return aliasAttrs;
      },

      getCodeValueFromTypes: function(field, typeIdField, types, obj, aliasAttrs) {
        var codeValue = null;
        if (typeIdField && types && types.length > 0) {
          var typeChecks = array.filter(types, lang.hitch(this, function(item) {
            // value of typeIdFild has been changed above
            return item.name === obj[typeIdField];
          }));
          var typeCheck = (typeChecks && typeChecks[0]) || null;

          if (typeCheck && typeCheck.domains &&
            typeCheck.domains[field.name] && typeCheck.domains[field.name].codedValues) {
            codeValue = jimuUtils.fieldFormatter.getCodedValue(
              typeCheck.domains[field.name],
              obj[field.name]
            );
          }
        }
        var fieldAlias = field.name;
        var _value = codeValue !== null ? codeValue : aliasAttrs[fieldAlias];
        return _value || isFinite(_value) ? _value : "";
      },

      _resetSelectorPosition: function(cls) {
        var layoutBox = html.getMarginBox(window.jimuConfig.layoutId);
        query(cls, this.domNode).forEach(lang.hitch(this, function(menu) {
          var menuPosition = html.position(menu);
          if (html.getStyle(menu, 'display') === 'none') {
            return;
          }
          var dijitPosition = html.position(this.searchDijit.domNode);
          var up = dijitPosition.y - 2;
          var down = layoutBox.h - dijitPosition.y - dijitPosition.h;
          if ((down > menuPosition.y + menuPosition.h) || (up > menuPosition.h)) {
            html.setStyle(
              menu,
              'top',
              (
                (down > menuPosition.y + menuPosition.h) ?
                dijitPosition.h : -menuPosition.h - 2
              ) + 'px'
            );
          } else {
            html.setStyle(menu, 'height', Math.max(down, up) + 'px');
            html.setStyle(menu, 'top', (down > up ? dijitPosition.h : -up - 2) + 'px');
          }
        }));
      },

      _onSourceIndexChange: function() {
        if (this.searchDijit.value) {
          this.searchDijit.search(this.searchDijit.value);
        }
      },

      _onSearchDijitClick: function() {
        this._resetSelectorPosition('.searchMenu');
      },

      _onSearchResults: function(evt) {
        var sources = this.searchDijit.get('sources');
        var activeSourceIndex = this.searchDijit.get('activeSourceIndex');
        var value = this.searchDijit.get('value');
        var htmlContent = "";
        var results = evt.results;
        var _activeSourceNumber = null;
        if (results && evt.numResults > 0) {
          html.removeClass(this.searchDijit.containerNode, 'showSuggestions');

          this.searchResults = results;
          htmlContent += '<div class="show-all-results jimu-ellipsis" title="' +
            this.nls.showAll + '">' +
            this.nls.showAllResults + '<strong >' + value + '</strong></div>';
          htmlContent += '<div class="searchMenu" role="menu">';
          for (var i in results) {
            if (results[i] && results[i].length) {
              var name = sources[parseInt(i, 10)].name;
              if (sources.length > 1 && activeSourceIndex === 'all') {
                htmlContent += '<div title="' + name + '" class="menuHeader">' + name + '</div>';
              }
              htmlContent += "<ul>";
              var partialMatch = value;
              var r = new RegExp("(" + partialMatch + ")", "gi");
              var maxResults = sources[i].maxResults;

              for (var j = 0, len = results[i].length; j < len && j < maxResults; j++) {
                var text = esriLang.isDefined(results[i][j].name) ?
                  results[i][j].name : this.nls.untitled;

                htmlContent += '<li title="' + text + '" data-index="' + j +
                  '" data-source-index="' + i + '" role="menuitem" tabindex="0">' +
                  text.toString().replace(r, "<strong >$1</strong>") + '</li>';
              }
              htmlContent += '</url>';

              if (evt.numResults === 1) {
                _activeSourceNumber = i;
              }
            }
          }
          htmlContent += "</div>";
          this.searchResultsNode.innerHTML = htmlContent;

          this._showResultMenu();

          this._resetSelectorPosition('.searchMenu');
        } else {
          this._onClearSearch();
        }
        // publish search results to other widgets
        this.publishData({
          'searchResults': evt
        });
      },

      _onSuggestResults: function(evt) {
        this._resetSelectorPosition('.searchMenu');

        this._hideResultMenu();
        // publish suggest results to other widgets
        this.publishData({
          'suggestResults': evt
        });
      },

      _onSelectSearchResult: function(evt) {
        var target = evt.target;
        while(!(html.hasAttr(target, 'data-source-index') && html.getAttr(target, 'data-index'))) {
          target = target.parentNode;
        }
        var result = null;
        var dataSourceIndex = html.getAttr(target, 'data-source-index');
        var dataIndex = parseInt(html.getAttr(target, 'data-index'), 10);
        // var sources = this.searchDijit.get('sources');

        if (dataSourceIndex !== 'all') {
          dataSourceIndex = parseInt(dataSourceIndex, 10);
        }
        if (this.searchResults && this.searchResults[dataSourceIndex] &&
          this.searchResults[dataSourceIndex][dataIndex]) {
          result = this.searchResults[dataSourceIndex][dataIndex];
          // clear before select.
          this.searchDijit.clearGraphics();
          this.searchDijit.select(result);
        }
      },

      _onSelectResult: function(e) {
        var result = e.result;
        if (!(result && result.name)) {
          return;
        }
        var dataSourceIndex = e.sourceIndex;
        var sourceResults = this.searchResults[dataSourceIndex];
        var dataIndex = 0;
        // var that = this;

        // var getGraphics = function(layer, fid) {
        //   var graphics = layer.graphics;
        //   var gs = array.filter(graphics, function(g) {
        //     return g.attributes[layer.objectIdField] === fid;
        //   });
        //   return gs;
        // };
        // var showPopupByFeatures = function(features) {
        //   var location = null;
        //   that.map.infoWindow.setFeatures(features);
        //   if (features[0].geometry.type === "point") {
        //     location = features[0].geometry;
        //   } else {
        //     location = features[0].geometry.getExtent().getCenter();
        //   }
        //   that.map.infoWindow.show(location, {
        //     closetFirst: true
        //   });
        // };

        for (var i = 0, len = sourceResults.length; i < len; i++) {
          if (jimuUtils.isEqual(sourceResults[i], result)) {
            dataIndex = i;
            break;
          }
        }
        query('li', this.searchResultsNode)
          .forEach(lang.hitch(this, function(li) {
            html.removeClass(li, 'result-item-selected');
            var title = html.getAttr(li, 'title');
            var dIdx = html.getAttr(li, 'data-index');
            var dsIndex = html.getAttr(li, 'data-source-index');

            if (title === result.name &&
              dIdx === dataIndex.toString() &&
              dsIndex === dataSourceIndex.toString()) {
              html.addClass(li, 'result-item-selected');
            }
          }));

        // var layer = this.map.getLayer(e.source._featureLayerId);

        // if (layer && this.config.showInfoWindowOnSelect) {
        //   var gs = getGraphics(layer, e.result.feature.__attributes[layer.objectIdField]);
        //   if (gs.length > 0) {
        //     showPopupByFeatures(gs);
        //   } else {
        //     var handle = on(layer, 'update-end', lang.hitch(this, function() {
        //       if (this.domNode) {
        //         var gs = getGraphics(layer, e.result.feature.__attributes[layer.objectIdField]);
        //         if (gs.length > 0) {
        //           showPopupByFeatures(gs);
        //         }
        //       }

        //       if (handle && handle.remove) {
        //         handle.remove();
        //       }
        //     }));
        //     this.own(handle);
        //   }
        // }
        // publish select result to other widgets
        this.publishData({
          'selectResult': e
        });

        // hide the graphic in map's default graphiclayer.
        // var _searchGL = this.searchDijit.graphicsLayer || this.map.graphics;
        // _searchGL.graphics.forEach(lang.hitch(this,function(item) {
        //   if (item && lang.getObject("_wabProperties.referToFeatureLayerId", false, item)) {
        //     // this.searchDijit.clearGraphics();
        //     _searchGL.remove(item);
        //   }
        // }));
      },

      _attatchOriLayerId: function(fs) {
        // Summary: attatchOriLayerId _attatch original featureLayer's ID.
        // Condition:
        //    1. Search dijit of JSAPI create new graphic and add it to map's default graphicslayer
        //      if no graphicslayer configured, map contains two same graphic at the same time.
        //    2. Attach original flayer's id as a property to graphic(map's default featurelayer),
        //      WAB can create related records with .

        // fs is an array, it's item could be 'esri.Graphic' or 'dojo.deferred'

        if (fs && fs.length && fs[0].declaredClass === "esri.Graphic" &&
          esriLang.isDefined(this._currentSelectSourceIdx)) {
          // iterator every item
          fs.forEach(lang.hitch(this, function(item) {
            // only type 'esri.Graphic'
            if (item.declaredClass === "esri.Graphic") {
              // original featurelayer id
              var _featureLayerId = this.searchDijit.sources[this._currentSelectSourceIdx]._featureLayerId;
              // get original featurelayer if exists.
              var layer = _featureLayerId && this.layerInfosObj.getLayerInfoById(_featureLayerId);
              // if original featurelayer added to map
              if (layer && this.config.showInfoWindowOnSelect) {
                // attatch original featurelayer's ID to this feature
                lang.setObject("_wabProperties.referToFeatureLayerId", _featureLayerId, item);
              }
            }
          }));
        }
      },

      _onClearSearch: function() {
        html.setStyle(this.searchResultsNode, 'display', 'none');
        this.searchResultsNode.innerHTML = "";
        this.searchResults = null;
      },

      _hideResultMenu: function() {
        query('.show-all-results', this.searchResultsNode).style('display', 'block');
        query('.searchMenu', this.searchResultsNode).style('display', 'none');
      },

      _showResultMenu: function() {
        html.setStyle(this.searchResultsNode, 'display', 'block');
        query('.show-all-results', this.searchResultsNode).style('display', 'none');
        query('.searchMenu', this.searchResultsNode).style('display', 'block');

        var groupNode = query('.searchInputGroup', this.searchDijit.domNode)[0];
        if (groupNode) {
          var groupBox = html.getMarginBox(groupNode);
          var style = {
            width: groupBox.w + 'px'
          };
          if (window.isRTL) {
            var box = html.getMarginBox(this.searchDijit.domNode);
            style.right = (box.w - groupBox.l - groupBox.w) + 'px';
          } else {
            style.left = groupBox.l + 'px';
          }
          query('.show-all-results', this.searchResultsNode).style(style);
          query('.searchMenu', this.searchResultsNode).style(style);
        }
      },

      destroy: function() {
        utils.setMap(null);
        utils.setLayerInfosObj(null);
        utils.setAppConfig(null);
        if (this.searchDijit) {
          this.searchDijit.clear();
        }

        this.inherited(arguments);
      },

      _hidePopup: function() {
        if (this.map.infoWindow.isShowing) {
          this.map.infoWindow.hide();
        }
      },

      onActive: function() {
        this._mapClickHandle = aspect.before(this.map, 'onClick', lang.hitch(this, function() {
          this._hidePopup();
          return arguments;
        }));
      },

      onDeActive: function() {
        if (this._mapClickHandle && this._mapClickHandle.remove) {
          this._mapClickHandle.remove();
        }
        this._hidePopup();
      }

    });
  });

View solution in original post

0 Kudos
24 Replies
RobertScheitlin__GISP
MVP Emeritus

David,

  I have been looking into this and it seems that the graphic that is added by the search widget is deleted and another graphic is added that has no symbology and the maps popup is the only thing that highlights it. When you close the popup the graphic is no longer seen on the map. So the cyan outline of the graphic is from the popups fillsymbol and not the search widgets source highlightsymbol. The search widget is still adding the graphic using the highlightsymbol but there is code to delete it. It seems that the intention is to get the actual graphic from the FeatureLayer so that it supports relates and attachment vs the graphic that the search widget normally shows which is pretty simple.

So the fix would depend on your desired workflow.

  1. I can provide code for setting the popups fill symbol to the highlightsymbol. This will work fine except when the popup is closed the highlight is removed. The possible issue with this is to re apply the popup fillsymbol after the search widget is done (results cleared).
  2. I can remove the portion of the code that deletes the search widgets graphic and the highlightsymbol will be used and the popup will still add the cyan outline over the graphic as well and be removed when the popup is closed. The search widget graphic using the highlightsymbol will still remain on the map until the search results are cleared.
  3. I can remove the portion of the code that deletes the search widgets graphic and the highlightsymbol will be used and then set the popup fill symbol to null to remove the cyan out line. The possible issue with this is to re apply the popup fillsymbol after the search widget is done (results cleared).
DavidColey
Frequent Contributor

Right thanks Robert.  I did glean that it seemed they are trying to have the search's popup behave like the map popup but have trouble following the logic.  I've been trying to console the event where the highlight is being removed without success so far. I tried commenting out line 677 and the section around 760 where the search's graphic layer is being removed.

I'd say since the original intent on this change was to replace the old faded orange graphic and then persist a graphic onscreen until the search result is cleared that I am trying to replicate your item 2 above.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

David,

  OK, then here is the whole file with my changes for option 2:

_onSelectResult lines 763 - 769 are the important new changes for 2.6 (commenting these lines).

///////////////////////////////////////////////////////////////////////////
// Copyright © 2015 Esri. All Rights Reserved.
//
// Licensed under the Apache License Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///////////////////////////////////////////////////////////////////////////

define([
    'dojo/_base/declare',
    'dojo/_base/lang',
    'dojo/_base/array',
    'dojo/_base/html',
    'dojo/when',
    'dojo/on',
    'dojo/aspect',
    'dojo/query',
    'dojo/keys',
    'dojo/Deferred',
    'dojo/promise/all',
    'jimu/BaseWidget',
    'jimu/LayerInfos/LayerInfos',
    'jimu/utils',
    'esri/dijit/Search',
    'esri/tasks/locator',
    'esri/layers/FeatureLayer',
    'esri/InfoTemplate',
    'esri/lang',
    './utils',
    'esri/symbols/jsonUtils', //for highlight change
    'dojo/NodeList-dom'
  ],
  function(declare, lang, array, html, when, on, aspect, query, keys, Deferred, all,
    BaseWidget, LayerInfos, jimuUtils, Search, Locator,
    FeatureLayer, InfoTemplate, esriLang, utils, jsonUtils) {
    //To create a widget, you need to derive from BaseWidget.
    return declare([BaseWidget], {
      name: 'Search',
      baseClass: 'jimu-widget-search',
      searchDijit: null,
      searchResults: null,

      _startWidth: null,

      postCreate: function() {
        if (this.closeable || !this.isOnScreen) {
          html.addClass(this.searchNode, 'default-width-for-openAtStart');
        }

        this.listenWidgetIds.push('framework');
      },

      startup: function() {
        this.inherited(arguments);

        if (!(this.config && this.config.sources)) {
          this.config.sources = [];
        }

        LayerInfos.getInstance(this.map, this.map.itemInfo)
          .then(lang.hitch(this, function(layerInfosObj) {
            this.layerInfosObj = layerInfosObj;
            this.own(this.layerInfosObj.on(
            'layerInfosFilterChanged',
            lang.hitch(this, this.onLayerInfosFilterChanged)));

            utils.setMap(this.map);
            utils.setLayerInfosObj(this.layerInfosObj);
            utils.setAppConfig(this.appConfig);
            when(utils.getConfigInfo(this.config)).then(lang.hitch(this, function(config) {
              return all(this._convertConfig(config)).then(function(searchSouces) {
                return array.filter(searchSouces, function(source) {
                  return source;
                });
              });
            })).then(lang.hitch(this, function(searchSouces) {
              if (!this.domNode) {
                return;
              }

              this.searchDijit = new Search({
                activeSourceIndex: searchSouces.length === 1 ? 0 : 'all',
                allPlaceholder: jimuUtils.stripHTML(esriLang.isDefined(this.config.allPlaceholder) ?
                  this.config.allPlaceholder : ""),
                autoSelect: true,
                enableButtonMode: false,
                enableLabel: false,
                enableInfoWindow: true,
                enableHighlight: esriLang.isDefined(this.config.showInfoWindowOnSelect) ?
                  !!this.config.showInfoWindowOnSelect : true,
                showInfoWindowOnSelect: esriLang.isDefined(this.config.showInfoWindowOnSelect) ?
                  !!this.config.showInfoWindowOnSelect : true,
                map: this.map,
                sources: searchSouces,
                theme: 'arcgisSearch'
              });
              html.place(this.searchDijit.domNode, this.searchNode);
              this.searchDijit.startup();

              this._resetSearchDijitStyle();

              this.own(
                this.searchDijit.watch(
                  'activeSourceIndex',
                  lang.hitch(this, '_onSourceIndexChange')
                )
              );

              this.own(
                on(this.searchDijit.domNode, 'click', lang.hitch(this, '_onSearchDijitClick'))
              );
              this.own(on(this.searchDijit.inputNode, "keyup", lang.hitch(this, function(e) {
                if (e.keyCode !== keys.ENTER) {
                  this._onClearSearch();
                }
              })));
              this.own(
                aspect.before(this.searchDijit, 'select', lang.hitch(this, '_captureSelect'))
                );
              this.own(
                on(this.searchDijit, 'search-results', lang.hitch(this, '_onSearchResults'))
              );
              this.own(
                on(this.searchDijit, 'suggest-results', lang.hitch(this, '_onSuggestResults'))
              );
              this.own(
                on(this.searchDijit, 'select-result', lang.hitch(this, '_onSelectResult'))
              );
              // attatch original feature layer's id.
              this.own(
                aspect.before(this.map.infoWindow, 'setFeatures', lang.hitch(this, '_attatchOriLayerId'))
              );
              // this.map.infoWindow has two different implementations (esri/dijit/Popup and esri/dijit/PopupMobile)
              //  after screen size changed. map switch it automatically.
              // here make sure fun:setFeatures be binded
              this._mapInfoWindow_ = this.map.infoWindow;
              var _winResizeHandler = on(window, 'resize', lang.hitch(this, function() {
                if (this._mapInfoWindow_ !== this.map.infoWindow) {
                  this.own(
                    aspect.before(this.map.infoWindow, 'setFeatures', lang.hitch(this, '_attatchOriLayerId'))
                  );
                  _winResizeHandler.remove();
                }
              }));
              this.own(
                on(this.searchResultsNode, 'li:click', lang.hitch(this, '_onSelectSearchResult'))
              );
              this.own(on(
                this.searchResultsNode,
                '.show-all-results:click',
                lang.hitch(this, '_showResultMenu')
              ));
              this.own(
                on(window.document, 'click', lang.hitch(this, function(e) {
                  if (!html.isDescendant(e.target, this.searchResultsNode)) {
                    this._hideResultMenu();
                    this._resetSelectorPosition('.show-all-results');
                  }
                }))
              );
              this.own(
                on(this.searchDijit, 'clear-search', lang.hitch(this, '_onClearSearch'))
              );
              this.own(
                aspect.after(this.map.infoWindow, 'show', lang.hitch(this, function() {
                  if (this.searchDijit &&
                    this.map.infoWindow.getSelectedFeature() !==
                    this.searchDijit.highlightGraphic) {
                    //this.searchDijit.clearGraphics();
                    query('li', this.searchResultsNode).removeClass('result-item-selected');
                  }
                }))
              );
              // this.own(
              //   on(this.map.infoWindow, 'show,hide', lang.hitch(this, function() {
              //     if (this.searchDijit &&
              //       this.map.infoWindow.getSelectedFeature() ===
              //       this.searchDijit.highlightGraphic) {
              //       this.searchDijit.clearGraphics();
              //       query('li', this.searchResultsNode).removeClass('result-item-selected');
              //     }
              //   }))
              // );

              this.fetchData('framework');
            }));
          }));
      },

      onReceiveData: function(name, widgetId, data) {
        if (name === 'framework' && widgetId === 'framework' && data && data.searchString) {
          this.searchDijit.set('value', data.searchString);
          this.searchDijit.search();
        }
      },

      setPosition: function(position) {
        this._resetSearchDijitStyle(position);
        this.inherited(arguments);
      },

      resize: function() {
        this._resetSearchDijitStyle();
      },

      onLayerInfosFilterChanged: function(changedLayerInfos) {
        array.some(changedLayerInfos, lang.hitch(this, function(info) {
          if (this.searchDijit && this.searchDijit.sources && this.searchDijit.sources.length > 0) {
            array.forEach(this.searchDijit.sources, function(s) {
              if (s._featureLayerId === info.id) {
                s.featureLayer.setDefinitionExpression(info.getFilter());
              }
            });
          }
        }));
      },

      _resetSearchDijitStyle: function() {
        html.removeClass(this.domNode, 'use-absolute');
        if (this.searchDijit && this.searchDijit.domNode) {
          html.setStyle(this.searchDijit.domNode, 'width', 'auto');
        }

        setTimeout(lang.hitch(this, function() {
          if (this.searchDijit && this.searchDijit.domNode) {
            var box = {
              w: !window.appInfo.isRunInMobile ? 274 : // original width of search dijit
                parseInt(html.getComputedStyle(this.domNode).width, 10)
            };
            var sourcesBox = html.getMarginBox(this.searchDijit.sourcesBtnNode);
            var submitBox = html.getMarginBox(this.searchDijit.submitNode);
            var style = null;
            if (box.w) {
              html.setStyle(this.searchDijit.domNode, 'width', box.w + 'px');
              html.addClass(this.domNode, 'use-absolute');

              if (isFinite(sourcesBox.w) && isFinite(submitBox.w)) {
                if (window.isRTL) {
                  style = {
                    left: submitBox.w + 'px',
                    right: sourcesBox.w + 'px'
                  };
                } else {
                  style = {
                    left: sourcesBox.w + 'px',
                    right: submitBox.w + 'px'
                  };
                }
                var inputGroup = query('.searchInputGroup', this.searchDijit.domNode)[0];

                if (inputGroup) {
                  html.setStyle(inputGroup, style);
                  var groupBox = html.getMarginBox(inputGroup);
                  var extents = html.getPadBorderExtents(this.searchDijit.inputNode);
                  html.setStyle(this.searchDijit.inputNode, 'width', groupBox.w - extents.w + 'px');
                }
              }
            }
          }
        }), 50);
      },

      _convertConfig: function(config) {
        var sourceDefs = array.map(config.sources, lang.hitch(this, function(source) {
          var def = new Deferred();
          if (source && source.url && source.type === 'locator') {
            var _source = {
              locator: new Locator(source.url || ""),
              outFields: ["*"],
              singleLineFieldName: source.singleLineFieldName || "",
              name: jimuUtils.stripHTML(source.name || ""),
              placeholder: jimuUtils.stripHTML(source.placeholder || ""),
              countryCode: source.countryCode || "",
              maxSuggestions: source.maxSuggestions,
              maxResults: source.maxResults || 6,
              zoomScale: source.zoomScale || 50000,
              useMapExtent: !!source.searchInCurrentMapExtent
            };

            if (source.enableLocalSearch) {
              _source.localSearchOptions = {
                minScale: source.localSearchMinScale,
                distance: source.localSearchDistance
              };
            }

            def.resolve(_source);
          } else if (source && source.url && source.type === 'query') {
            var searchLayer = new FeatureLayer(source.url || null, {
              outFields: ["*"]
            });

            this.own(on(searchLayer, 'load', lang.hitch(this, function(result) {
              var flayer = result.layer;
              var template = this._getInfoTemplate(flayer, source, source.displayField);
              var fNames = null;
              if (source.searchFields && source.searchFields.length > 0) {
                fNames = source.searchFields;
              } else {
                fNames = [];
                array.forEach(flayer.fields, function(field) {
                  if (field.type !== "esriFieldTypeOID" && field.name !== flayer.objectIdField &&
                    field.type !== "esriFieldTypeGeometry") {
                    fNames.push(field.name);
                  }
                });
              }
              var convertedSource = {
                featureLayer: flayer,
                outFields: ["*"],
                searchFields: fNames,
                displayField: source.displayField || "",
                exactMatch: !!source.exactMatch,
                name: jimuUtils.stripHTML(source.name || ""),
                placeholder: jimuUtils.stripHTML(source.placeholder || ""),
                maxSuggestions: source.maxSuggestions || 6,
                maxResults: source.maxResults || 6,
                zoomScale: source.zoomScale || 50000,
                infoTemplate: template,
                useMapExtent: !!source.searchInCurrentMapExtent,
                _featureLayerId: source.layerId
              };
              if(source.highlightSymbol){
                convertedSource.highlightSymbol = jsonUtils.fromJson(source.highlightSymbol);
                //this.map.infoWindow.fillSymbol = jsonUtils.fromJson(source.highlightSymbol);
              }
              if (!template) {
                delete convertedSource.infoTemplate;
              }
              if (convertedSource._featureLayerId) {
                var layerInfo = this.layerInfosObj
                  .getLayerInfoById(convertedSource._featureLayerId);
                flayer.setDefinitionExpression(layerInfo.getFilter());
              }
              def.resolve(convertedSource);
            })));

            this.own(on(searchLayer, 'error', function() {
              def.resolve(null);
            }));
          } else {
            def.resolve(null);
          }
          return def;
        }));

        return sourceDefs;
      },

      _getInfoTemplate: function(fLayer, source, displayField) {
        var layerInfo = this.layerInfosObj.getLayerInfoById(source.layerId);
        var template = layerInfo && layerInfo.getInfoTemplate();
        var validTemplate = layerInfo && template;

        if (layerInfo && !validTemplate) { // doesn't enabled pop-up
          return null;
        } else if (validTemplate) {
          // configured media or attachments
          return template;
        } else { // (added by user in setting) or (only configured fieldInfo)
          template = new InfoTemplate();
          template.setTitle(' ');
          template.setContent(
            lang.hitch(this, '_formatContent', source.name, fLayer, displayField)
          );

          return template;
        }
      },

      _getSourcePopupInfo: function(source) {
        if (source._featureLayerId) {
          var layerInfo = this.layerInfosObj.getLayerInfoById(source._featureLayerId);
          if (layerInfo) {
            return layerInfo.getPopupInfo();
          }
        }
        return null;
      },

      _captureSelect: function(e) {
        var sourceIndex = this.searchDijit.activeSourceIndex;
        if (sourceIndex === 'all') {
          sourceIndex = this._getSourceIndexOfResult(e);
        }
        if (isFinite(sourceIndex) && esriLang.isDefined(sourceIndex)) {
          // record current select source index, for FUN:_attatchOriLayerId.
          this._currentSelectSourceIdx = sourceIndex;
          var source = this.searchDijit.sources[sourceIndex];
          if (source && 'featureLayer' in source) {
            var popupInfo = this._getSourcePopupInfo(source);
            var notFormatted = (popupInfo && popupInfo.showAttachments) ||
              (popupInfo && popupInfo.description &&
              popupInfo.description.match(/http(s)?:\/\//)) ||
              (popupInfo && popupInfo.mediaInfos && popupInfo.mediaInfos.length > 0);

            // set a private property for select-result to get original feature from layer.
            if (!e.feature.__attributes) {
              e.feature.__attributes = e.feature.attributes;
            }

            if (!notFormatted) {
              var formatedAttrs = this._getFormatedAttrs(
                lang.clone(e.feature.attributes),
                source.featureLayer.fields,
                source.featureLayer.typeIdField,
                source.featureLayer.types,
                popupInfo
              );

              e.feature.attributes = formatedAttrs;
            }
          }
        }

        return [e];
      },

      _getSourceIndexOfResult: function(e) {
        if (this.searchResults){
          for (var i in this.searchResults) {
            var sourceResults = this.searchResults[i];
            var pos = array.indexOf(sourceResults, e);
            if (pos > -1) {
              return parseInt(i, 10);
            }
          }
        }

        return null;
      },

      _formatContent: function(title, fLayer, displayField, graphic) {
        var content = "";
        if (graphic && graphic.attributes && fLayer && fLayer.url) {
          var aliasAttrs = {};
          array.forEach(fLayer.fields, lang.hitch(this, function(field) {
            if (field.name in graphic.attributes){
              aliasAttrs[field.alias || field.name] = graphic.attributes[field.name];
            }
          }));
          var displayValue = graphic.attributes[displayField];
          content += '<div class="esriViewPopup">' +
            '<div class="mainSection">' +
            (esriLang.isDefined(displayValue) ?
              ('<div class="header">' + title + ': ' + displayValue + '</div>') : "") +
            '<div class="hzLine"></div>' +
            '<div>' +
            '<table class="attrTable" cellpading="0" cellspacing="0">' +
            '<tbody>';
          for (var p in aliasAttrs) {
            if (aliasAttrs.hasOwnProperty(p)) {
              content += '<tr valign="top">' +
                '<td class="attrName">' + p + '</td>' +
                '<td class="attrValue">' + aliasAttrs[p] + '</td>' +
                '</tr>';
            }
          }
          content += '</tbody>' +
            '</table>' +
            '</div>' +
            '<div class="break"></div>' +
            '</div>';
        }

        return content;
      },

      _getFormatedAttrs: function(attrs, fields, typeIdField, types, popupInfo) {
        function getFormatInfo(fieldName) {
          if (popupInfo && esriLang.isDefined(popupInfo.fieldInfos)) {
            for (var i = 0, len = popupInfo.fieldInfos.length; i < len; i++) {
              var f = popupInfo.fieldInfos[i];
              if (f.fieldName === fieldName) {
                return f.format;
              }
            }
          }

          return null;
        }

        var aliasAttrs = {};
        array.forEach(fields, lang.hitch(this, function(_field, i) {
          if (!attrs[_field.name]) {
            return;
          }
          var isCodeValue = !!(_field.domain && _field.domain.type === 'codedValue');
          var isDate = _field.type === "esriFieldTypeDate";
          var isTypeIdField = typeIdField && (_field.name === typeIdField);
          var fieldAlias = _field.name;

          if (fields[i].type === "esriFieldTypeDate") {
            aliasAttrs[fieldAlias] = jimuUtils.fieldFormatter.getFormattedDate(
              attrs[_field.name], getFormatInfo(_field.name)
              );
          } else if (fields[i].type === "esriFieldTypeDouble" ||
            fields[i].type === "esriFieldTypeSingle" ||
            fields[i].type === "esriFieldTypeInteger" ||
            fields[i].type === "esriFieldTypeSmallInteger") {
            aliasAttrs[fieldAlias] = jimuUtils.fieldFormatter.getFormattedNumber(
              attrs[_field.name], getFormatInfo(_field.name)
              );
          }

          if (isCodeValue) {
            aliasAttrs[fieldAlias] = jimuUtils.fieldFormatter.getCodedValue(
              _field.domain, attrs[_field.name]
              );
          } else if (isTypeIdField) {
            aliasAttrs[fieldAlias] = jimuUtils.fieldFormatter.getTypeName(
              attrs[_field.name], types
              );
          } else if (!isCodeValue && !isDate && !isTypeIdField) {
            // Not A Date, Domain or Type Field
            // Still need to check for codedType value
            aliasAttrs[fieldAlias] = fieldAlias in aliasAttrs ?
              aliasAttrs[fieldAlias] : attrs[_field.name];
            aliasAttrs[fieldAlias] = this.getCodeValueFromTypes(
              _field,
              typeIdField,
              types,
              attrs,
              aliasAttrs
            );
          }
        }));
        return aliasAttrs;
      },

      getCodeValueFromTypes: function(field, typeIdField, types, obj, aliasAttrs) {
        var codeValue = null;
        if (typeIdField && types && types.length > 0) {
          var typeChecks = array.filter(types, lang.hitch(this, function(item) {
            // value of typeIdFild has been changed above
            return item.name === obj[typeIdField];
          }));
          var typeCheck = (typeChecks && typeChecks[0]) || null;

          if (typeCheck && typeCheck.domains &&
            typeCheck.domains[field.name] && typeCheck.domains[field.name].codedValues) {
            codeValue = jimuUtils.fieldFormatter.getCodedValue(
              typeCheck.domains[field.name],
              obj[field.name]
            );
          }
        }
        var fieldAlias = field.name;
        var _value = codeValue !== null ? codeValue : aliasAttrs[fieldAlias];
        return _value || isFinite(_value) ? _value : "";
      },

      _resetSelectorPosition: function(cls) {
        var layoutBox = html.getMarginBox(window.jimuConfig.layoutId);
        query(cls, this.domNode).forEach(lang.hitch(this, function(menu) {
          var menuPosition = html.position(menu);
          if (html.getStyle(menu, 'display') === 'none') {
            return;
          }
          var dijitPosition = html.position(this.searchDijit.domNode);
          var up = dijitPosition.y - 2;
          var down = layoutBox.h - dijitPosition.y - dijitPosition.h;
          if ((down > menuPosition.y + menuPosition.h) || (up > menuPosition.h)) {
            html.setStyle(
              menu,
              'top',
              (
                (down > menuPosition.y + menuPosition.h) ?
                dijitPosition.h : -menuPosition.h - 2
              ) + 'px'
            );
          } else {
            html.setStyle(menu, 'height', Math.max(down, up) + 'px');
            html.setStyle(menu, 'top', (down > up ? dijitPosition.h : -up - 2) + 'px');
          }
        }));
      },

      _onSourceIndexChange: function() {
        if (this.searchDijit.value) {
          this.searchDijit.search(this.searchDijit.value);
        }
      },

      _onSearchDijitClick: function() {
        this._resetSelectorPosition('.searchMenu');
      },

      _onSearchResults: function(evt) {
        var sources = this.searchDijit.get('sources');
        var activeSourceIndex = this.searchDijit.get('activeSourceIndex');
        var value = this.searchDijit.get('value');
        var htmlContent = "";
        var results = evt.results;
        var _activeSourceNumber = null;
        if (results && evt.numResults > 0) {
          html.removeClass(this.searchDijit.containerNode, 'showSuggestions');

          this.searchResults = results;
          htmlContent += '<div class="show-all-results jimu-ellipsis" title="' +
            this.nls.showAll + '">' +
            this.nls.showAllResults + '<strong >' + value + '</strong></div>';
          htmlContent += '<div class="searchMenu" role="menu">';
          for (var i in results) {
            if (results[i] && results[i].length) {
              var name = sources[parseInt(i, 10)].name;
              if (sources.length > 1 && activeSourceIndex === 'all') {
                htmlContent += '<div title="' + name + '" class="menuHeader">' + name + '</div>';
              }
              htmlContent += "<ul>";
              var partialMatch = value;
              var r = new RegExp("(" + partialMatch + ")", "gi");
              var maxResults = sources[i].maxResults;

              for (var j = 0, len = results[i].length; j < len && j < maxResults; j++) {
                var text = esriLang.isDefined(results[i][j].name) ?
                  results[i][j].name : this.nls.untitled;

                htmlContent += '<li title="' + text + '" data-index="' + j +
                  '" data-source-index="' + i + '" role="menuitem" tabindex="0">' +
                  text.toString().replace(r, "<strong >$1</strong>") + '</li>';
              }
              htmlContent += '</url>';

              if (evt.numResults === 1) {
                _activeSourceNumber = i;
              }
            }
          }
          htmlContent += "</div>";
          this.searchResultsNode.innerHTML = htmlContent;

          this._showResultMenu();

          this._resetSelectorPosition('.searchMenu');
        } else {
          this._onClearSearch();
        }
        // publish search results to other widgets
        this.publishData({
          'searchResults': evt
        });
      },

      _onSuggestResults: function(evt) {
        this._resetSelectorPosition('.searchMenu');

        this._hideResultMenu();
        // publish suggest results to other widgets
        this.publishData({
          'suggestResults': evt
        });
      },

      _onSelectSearchResult: function(evt) {
        var target = evt.target;
        while(!(html.hasAttr(target, 'data-source-index') && html.getAttr(target, 'data-index'))) {
          target = target.parentNode;
        }
        var result = null;
        var dataSourceIndex = html.getAttr(target, 'data-source-index');
        var dataIndex = parseInt(html.getAttr(target, 'data-index'), 10);
        // var sources = this.searchDijit.get('sources');

        if (dataSourceIndex !== 'all') {
          dataSourceIndex = parseInt(dataSourceIndex, 10);
        }
        if (this.searchResults && this.searchResults[dataSourceIndex] &&
          this.searchResults[dataSourceIndex][dataIndex]) {
          result = this.searchResults[dataSourceIndex][dataIndex];
          // clear before select.
          this.searchDijit.clearGraphics();
          this.searchDijit.select(result);
        }
      },

      _onSelectResult: function(e) {
        var result = e.result;
        if (!(result && result.name)) {
          return;
        }
        var dataSourceIndex = e.sourceIndex;
        var sourceResults = this.searchResults[dataSourceIndex];
        var dataIndex = 0;
        // var that = this;

        // var getGraphics = function(layer, fid) {
        //   var graphics = layer.graphics;
        //   var gs = array.filter(graphics, function(g) {
        //     return g.attributes[layer.objectIdField] === fid;
        //   });
        //   return gs;
        // };
        // var showPopupByFeatures = function(features) {
        //   var location = null;
        //   that.map.infoWindow.setFeatures(features);
        //   if (features[0].geometry.type === "point") {
        //     location = features[0].geometry;
        //   } else {
        //     location = features[0].geometry.getExtent().getCenter();
        //   }
        //   that.map.infoWindow.show(location, {
        //     closetFirst: true
        //   });
        // };

        for (var i = 0, len = sourceResults.length; i < len; i++) {
          if (jimuUtils.isEqual(sourceResults[i], result)) {
            dataIndex = i;
            break;
          }
        }
        query('li', this.searchResultsNode)
          .forEach(lang.hitch(this, function(li) {
            html.removeClass(li, 'result-item-selected');
            var title = html.getAttr(li, 'title');
            var dIdx = html.getAttr(li, 'data-index');
            var dsIndex = html.getAttr(li, 'data-source-index');

            if (title === result.name &&
              dIdx === dataIndex.toString() &&
              dsIndex === dataSourceIndex.toString()) {
              html.addClass(li, 'result-item-selected');
            }
          }));

        // var layer = this.map.getLayer(e.source._featureLayerId);

        // if (layer && this.config.showInfoWindowOnSelect) {
        //   var gs = getGraphics(layer, e.result.feature.__attributes[layer.objectIdField]);
        //   if (gs.length > 0) {
        //     showPopupByFeatures(gs);
        //   } else {
        //     var handle = on(layer, 'update-end', lang.hitch(this, function() {
        //       if (this.domNode) {
        //         var gs = getGraphics(layer, e.result.feature.__attributes[layer.objectIdField]);
        //         if (gs.length > 0) {
        //           showPopupByFeatures(gs);
        //         }
        //       }

        //       if (handle && handle.remove) {
        //         handle.remove();
        //       }
        //     }));
        //     this.own(handle);
        //   }
        // }
        // publish select result to other widgets
        this.publishData({
          'selectResult': e
        });

        // hide the graphic in map's default graphiclayer.
        // var _searchGL = this.searchDijit.graphicsLayer || this.map.graphics;
        // _searchGL.graphics.forEach(lang.hitch(this,function(item) {
        //   if (item && lang.getObject("_wabProperties.referToFeatureLayerId", false, item)) {
        //     // this.searchDijit.clearGraphics();
        //     _searchGL.remove(item);
        //   }
        // }));
      },

      _attatchOriLayerId: function(fs) {
        // Summary: attatchOriLayerId _attatch original featureLayer's ID.
        // Condition:
        //    1. Search dijit of JSAPI create new graphic and add it to map's default graphicslayer
        //      if no graphicslayer configured, map contains two same graphic at the same time.
        //    2. Attach original flayer's id as a property to graphic(map's default featurelayer),
        //      WAB can create related records with .

        // fs is an array, it's item could be 'esri.Graphic' or 'dojo.deferred'

        if (fs && fs.length && fs[0].declaredClass === "esri.Graphic" &&
          esriLang.isDefined(this._currentSelectSourceIdx)) {
          // iterator every item
          fs.forEach(lang.hitch(this, function(item) {
            // only type 'esri.Graphic'
            if (item.declaredClass === "esri.Graphic") {
              // original featurelayer id
              var _featureLayerId = this.searchDijit.sources[this._currentSelectSourceIdx]._featureLayerId;
              // get original featurelayer if exists.
              var layer = _featureLayerId && this.layerInfosObj.getLayerInfoById(_featureLayerId);
              // if original featurelayer added to map
              if (layer && this.config.showInfoWindowOnSelect) {
                // attatch original featurelayer's ID to this feature
                lang.setObject("_wabProperties.referToFeatureLayerId", _featureLayerId, item);
              }
            }
          }));
        }
      },

      _onClearSearch: function() {
        html.setStyle(this.searchResultsNode, 'display', 'none');
        this.searchResultsNode.innerHTML = "";
        this.searchResults = null;
      },

      _hideResultMenu: function() {
        query('.show-all-results', this.searchResultsNode).style('display', 'block');
        query('.searchMenu', this.searchResultsNode).style('display', 'none');
      },

      _showResultMenu: function() {
        html.setStyle(this.searchResultsNode, 'display', 'block');
        query('.show-all-results', this.searchResultsNode).style('display', 'none');
        query('.searchMenu', this.searchResultsNode).style('display', 'block');

        var groupNode = query('.searchInputGroup', this.searchDijit.domNode)[0];
        if (groupNode) {
          var groupBox = html.getMarginBox(groupNode);
          var style = {
            width: groupBox.w + 'px'
          };
          if (window.isRTL) {
            var box = html.getMarginBox(this.searchDijit.domNode);
            style.right = (box.w - groupBox.l - groupBox.w) + 'px';
          } else {
            style.left = groupBox.l + 'px';
          }
          query('.show-all-results', this.searchResultsNode).style(style);
          query('.searchMenu', this.searchResultsNode).style(style);
        }
      },

      destroy: function() {
        utils.setMap(null);
        utils.setLayerInfosObj(null);
        utils.setAppConfig(null);
        if (this.searchDijit) {
          this.searchDijit.clear();
        }

        this.inherited(arguments);
      },

      _hidePopup: function() {
        if (this.map.infoWindow.isShowing) {
          this.map.infoWindow.hide();
        }
      },

      onActive: function() {
        this._mapClickHandle = aspect.before(this.map, 'onClick', lang.hitch(this, function() {
          this._hidePopup();
          return arguments;
        }));
      },

      onDeActive: function() {
        if (this._mapClickHandle && this._mapClickHandle.remove) {
          this._mapClickHandle.remove();
        }
        this._hidePopup();
      }

    });
  });
0 Kudos
DavidColey
Frequent Contributor

Yep, thanks Robert that's it - for our use cases this is how we have things functioning.  Looks like the highlightSymbol property can be added either in your IF statement at line 315 or can remain as an option in the convertedSource var.  Looks like I was close to discovering on my own where to comment out lines to persist the graphic - nevertheless I appreciate your eyes on this. 

The only other thing I'd say is it looks like for this release that esri hadn't fully completed the code for this build - hence all of the 2.5 commented code sections.  

0 Kudos
DavidColey
Frequent Contributor

Hi Robert et al - FYI it looks like the widget.js code has been re-worked some for 2.7, esp the _onSelectResult function (beginning around line 755).  Since this section of the code:

// hide the graphic in map's default graphiclayer. 
 // var _searchGL = this.searchDijit.graphicsLayer || this.map.graphics; ***This section commented to persist highlightsymbol on screen after infowindow close****
 // _searchGL.graphics.forEach(lang.hitch(this,function(item) {
 // if (item && lang.getObject("_wabProperties.referToFeatureLayerId", false, item)) {
 // // this.searchDijit.clearGraphics();
 // _searchGL.remove(item);
 // }
 // }));

has been removed, the only change I made to persist a highlight symbol upon info window close is under the converted source var:

if(source.highlightSymbol){
                convertedSource.highlightSymbol = jsonUtils.fromJson(source.highlightSymbol);
                //this.map.infoWindow.fillSymbol = jsonUtils.fromJson(source.highlightSymbol);
              }

as before. 

DavidColey
Frequent Contributor

Hi Robert et al - For 2.8, in order to persist a defined highlight symbol after info window close, comment out the clearGraphics method around line 754 of the Widget.js:

_loadInfoTemplateAndShowPopup: function(layerInfo, selectedFeature, selectEvent) {
    if(layerInfo) {
       //this.searchDijit.clearGraphics(); comment out to persist highlight graphic
       var layerObjectInMap = this.map.getLayer(layerInfo.id);
       if(layerInfo.isPopupEnabled() && layerObjectInMap) {
          this._showPopupByFeatures(layerInfo, [selectedFeature], selectEvent);
       } else {
          layerInfo.loadInfoTemplate().then(lang.hitch(this, function(infoTemplate) {
             //temporary set infoTemplate to selectedFeature.
          selectedFeature.setInfoTemplate(lang.clone(infoTemplate));
          this._showPopupByFeatures(layerInfo, [selectedFeature], selectEvent);
          // clear infoTemplate for selectedFeature;
          var handle = aspect.before(this.map, 'onClick', lang.hitch(this, function() {
             selectedFeature.setInfoTemplate(null);
             handle.remove();
             }));
          }));
       }
    }
 },

continue to create your highlight symbol as in 2.7 (around line 343):

if(source.highlightSymbol){ //to add highlight symbol from json
    convertedSource.highlightSymbol = jsonUtils.fromJson(source.highlightSymbol);
 //this.map.infoWindow.fillSymbol = jsonUtils.fromJson(source.highlightSymbol);
 }
JenniferSherry1
New Contributor

Hi David and Robert, I've been poring over this thread trying to glean the info I need without luck.  You two seem to have the most intimate knowledge with this search widget so I'm reaching out to you for some help.

I'm using WAB dev 2.8, and the behavior for the search widget that I'd like to modify includes the searched line feature being zoomed to and highlighted (I'm okay with the default highlight symbol), but I don't want the popup. I can't seem to figure out how to get one without the other.  I've looked all over for 2 days for insight.  Do either of you have any ideas?

I'm new to posting here, so I apologize if I should start a new thread instead.

Thanks!

Jennifer

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Jennifer,

   The Popup is what does the highlight so you can't have the highlight without the popup without re-coding a lot of the widget.

by Anonymous User
Not applicable

Hey Robert! Can you provide the code for removing the orange graphic completely? The resulting graphic_layer doesn't do too much for us and it'd be a lot easier if the feature search in the search widget behaved with parity to searching against a geocoder.

0 Kudos