filtering Geocoder for a specific country

9043
9
Jump to solution
01-05-2015 04:18 PM
DavidMarquardt
New Contributor III

Hello,

I'm trying to filter esri's geocoder for a specific country.  I've had some success, but nothing works extremely well.  I would have thought simply adding sourceCountry = "xxx" to the parameters of the arcgisGeocoder would work, but I couldn't get it to zoom correctly.   here are the three versions I've found:

1. attach a condition to the URL

2. go with no filter

3. use suffix = ", USA"

I'm attaching a code snippet as well below of these.

I'm wondering: Has anyone found a better way to filter the autocomplete options and have the map zoom to the correct coordinates?

//1. this one works okay, but the autofill is much slower than the others

   

   var myGeocoders = [{

          url: "http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer?sourceCountry=USA",

          name: "EsriWorldLocator",

          placeholder: "Find a place",

          autoComplete: true,

         singleLineFieldName: "SingleLine"

    }];

   

   

    var geocoder = new Geocoder ({

        map: map,

        arcgisGeocoder: false,

        geocoders: myGeocoders

        }, dom.byId("search")

        );

    geocoder.autoComplete = true;

   

    //2. This is the original, no filter

   

    var geocoder =  new Geocoder({

      arcgisGeocoder: {

     

        placeholder: "Find a place"

      },

      autoComplete: true,

      map: map

    }, dom.byId("search")

    );   

   

   

   

    //3.  This one has a great autocomplete, but it zooms to a seemingly random location

   

    var geocoder =  new Geocoder({

      arcgisGeocoder: {

        //sourceCountry: "USA",

        suffix: ", USA",

        placeholder: "Find a place"

      },

      autoComplete: true,

      autoNavigate: true,

      map: map

    }, dom.byId("search")

    );   

0 Kudos
1 Solution

Accepted Solutions
KellyHutchins
Esri Frequent Contributor

Ok so I see the issue. If you have autocomplete on and use the suffix then if you choose a suggestion from the list USA will be appended. So with autocomplete enabled its probably best to avoid the suffix.  One option that may work for you is to use the searchExtent to restrict the geocode results. I tested this with your code and it returned the correct results for the DC address.

   var geocoder = new Geocoder({

          map: map,

          autoComplete:true,

          arcgisGeocoder:{

            sourceCountry:"US",

            searchExtent: map.extent

          }

        }, "search");

    geocoder.startup();

View solution in original post

9 Replies
KellyHutchins
Esri Frequent Contributor

David,

Using something like this should work to restrict the search to a particular country.

        var geocoder = new Geocoder({
          map: map,
          autoComplete:true,
          arcgisGeocoder:{
            sourceCountry:"US",
            suffix: ", USA"
          }
        }, "search");
        geocoder.startup();

Looks like you tried this but said that the results zoomed you to a random location. Can you provide more details? For example what was the address info you entered? And where did it zoom you?

0 Kudos
DavidMarquardt
New Contributor III

Kelly,

Thanks for the reply.  I put this snippet in my code, and it autocompleted correctly, but it didn't zoom to the address.  It looks like the event doesn't get correctly created on the geocoder select event.  

If I comment out the sourceCountry, and leave the suffix, an address in the US (2028 N st SE, Washington DC 20020) zoomed to the mountains north of Luzon, Philippines.

I'm attaching a modified sample of what I'm doing.  Bascially, I'm using the map point from the geocoder within an identifyTask (it takes awhile for the popup to appear).

Your thoughts are appreciated,

David

Here's the sample code below:

<!DOCTYPE html>

<html>

  <head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <!--The viewport meta tag is used to improve the presentation and behavior of the samples

      on iOS devices-->

    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">

    <title>Identify with Popup</title>

    <link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">

    <style>

      html, body, #map {

        height:100%;

        width:100%;

        margin:0;

        padding:0;

      }

     

      #buttons{

  position: absolute;

  top:  0px;

    right: 10px;

  height: 20px;

  float:right;

  z-index:99;

  box-shadow: none;

  font-size:13px;

    font-family: arial narrow, helvetica, sans serif;

    font-weight: bold;

  /*padding: 1px 2px 1px;*/

}

#search {

  /* search contains esriGeocoderContainer */

  float: right;

  margin-top:-8px;

  padding: 10px;

  height: 59px;

    z-index: 199;

  }

#search .esriGeocoderContainer {

  position: relative;

  margin-top: 1px;

}

#search .esriGeocoder {

  box-shadow: 5px 5px 6px #888888;

  height: 18px;

  border-radius: 5px;

    border-color: #C0C0C0 #C0C0C0 #9B9B9B;

    border-image: none;

    border-style: solid;

    border-width: 1px;

    /*padding: 0.1em 0.2em 0.2em;*/

  padding: 1.3px 2.6px 1.3px;*/

  /*padding: 0.1em 0.2em 0.1em;*/

}

#search .esriGeocoderSearch.esriGeocoderIcon {

  position: relative;

  top: -3px;*/

}

#search_input  {

  padding: 4px;*/

  font-family:arial, helvetica, sans-serif;

  font-style: normal;

  font-size:13px;

  top:3px;

}

#search .esriGeocoderReset.esriGeocoderIcon {

  position: relative;

  top: -20%;

}

     

    .topButton {

        border-radius: 5px 5px 5px 5px;

        box-shadow: 5px 5px 6px #888888;

        background-color: #637851 !important;

        top: 50px;

    }

    .topButton .dijitButtonNode {

    padding: 0 0 0 0 !important;

    margin: 0 0 0 0!important;

    }

   

   

    span.dijitReset.dijitInline.dijitButtonNode{

        border: 0px;

        border-top-width: 0px !important;

        padding-top:0px;

        margin:0 0 0 0;

        background: transparent;

        color: white;

        font-weight: bold;

        border-style: none;

        box-shadow: none;

        -moz-box-shadow:    none;

        -webkit-box-shadow: none;

        box-shadow:         none;

    }

     

      #pup {

          position:absolute;

          z-index:200; /* aaaalways on top*/

          padding: 3px;

          margin-left: 20px;

          margin-top: 5px;

          width: auto;

          border: 1px solid black;

          background-color: #777;

          color: white;

          font-size: 0.95em;

          visibility:hidden;

        }

       

       

    #info {

      position: absolute;

      left:7px;

      bottom: 10px;

      padding: 2px;

      min-width:100px;

      background-color: #fff;

      /*text-align: center;*/

      border-radius: 5px 5px 5px 5px;

      z-index: 99;

      font:  12px  Helvetica, sans-serif;

    }

    #info table, th, td {

      border: 0px solid white;

    }

    #units {

      font-weight: bold;

      padding: 5px 5px 5px 5px;

    }

    </style>

    <script src="http://js.arcgis.com/3.11/"></script>

    <script src="http://code.jquery.com/jquery-1.9.1.js"></script>

    <script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>

    <script src="scripts/nhpup_1_1.js" type="text/javascript"></script>

    <script>

      var map;

     var hoverLbl = "";

     var app = [];

      require([

        "esri/map",

        "esri/InfoTemplate",

        "esri/request",

        "esri/dijit/InfoWindow",

        "esri/arcgis/utils",

        "esri/layers/ArcGISDynamicMapServiceLayer",

        "esri/layers/ArcGISTiledMapServiceLayer",

        "esri/layers/FeatureLayer",

        "esri/layers/ImageParameters",

        "esri/symbols/SimpleFillSymbol",

        "esri/symbols/SimpleLineSymbol",

        "esri/symbols/SimpleMarkerSymbol",

        "esri/tasks/IdentifyTask",

        "esri/tasks/IdentifyParameters",

        "esri/tasks/query",

        "esri/tasks/QueryTask",

        "esri/dijit/Popup",

        "esri/dijit/Geocoder",

        "dojo/_base/array",

        "esri/Color",

        "esri/graphic",

        "dojo/dom",

        "dojo/dom-construct",

        "dojo/dom-class",

        "dojo/string",

        "dojo/_base/lang",

        "dojo/data/ItemFileReadStore",       

        "dojo/domReady!"

      ], function (

        Map, InfoTemplate, esriRequest, InfoWindow,  arcgisUtils, ArcGISDynamicMapServiceLayer, ArcGISTiledMapServiceLayer, FeatureLayer, ImageParameters, SimpleFillSymbol,

        SimpleLineSymbol, SimpleMarkerSymbol, IdentifyTask, IdentifyParameters, Query, QueryTask, Popup, Geocoder,

        arrayUtils, Color, Graphic, dom, domConstruct, domClass, dojoString, lang, ItemFileReadStore

      ) {

        var identifyTask, identifyParams, geom1, selAddress, score, urban, suburban, identifyTaskClk, identifyParamsClk;

        var ext = new esri.geometry.Extent({ "xmin": -17529487, "ymin": 1874364, "xmax": -5084316, "ymax": 7500129, "spatialReference": { "wkid": 102100} });

        var countyN = "County";  

        var countyL = "3";

       /****************************************** create map and legends ********************************************************/

       map = new Map("map", {

          extent: ext

        })

        map.on("load", mapReady);

       

        var tiledService = "http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer";

        var featureURL = "http://server.arcgisonline.com/arcgis/rest/services/Demographics/USA_Diversity_Index/MapServer";

       

        map.addLayer(new ArcGISTiledMapServiceLayer(tiledService, {id: "basemap"}));

       

        var imageParameters = new ImageParameters();

        imageParameters.format = "png32";

        demoService = new ArcGISDynamicMapServiceLayer(featureURL, {

            id: countyN,

            opacity: 0.80});

        demoService.setVisibleLayers([3]);

       

       

       

        map.addLayer(demoService);

        getLegend(featureURL);

   

    /*************************************** geocoder **************************************************************/

  

    // I have three ways I'm trying to use to get my geocoder to have autocomplete filter for USA addresses only.

    //1. this one works okay, but the autofill is much slower than the others

    /*

   var myGeocoders = [{

          url: "http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer?sourceCountry=USA",

          name: "EsriWorldLocator",

          placeholder: "Find a place",

          autoComplete: true,

         singleLineFieldName: "SingleLine"

    }];

   

   

    var geocoder = new Geocoder ({

        map: map,

        arcgisGeocoder: false,

        geocoders: myGeocoders

        }, dom.byId("search")

        );

    geocoder.autoComplete = true;

    /*

    //2. This is the original, no filter

    /*

    var geocoder =  new Geocoder({

      arcgisGeocoder: {

     

        placeholder: "Find a place"

      },

      autoComplete: true,

      map: map

    }, dom.byId("search")

    );   

    */

   

   

    //3.  This one has a great autocomplete, but it zooms to a seemingly random location

    /*

    var geocoder =  new Geocoder({

      arcgisGeocoder: {

        //sourceCountry: "USA",

        suffix: ", USA",

        placeholder: "Find a place"

      },

      autoComplete: true,

      autoNavigate: true,

      map: map

    }, dom.byId("search")

    );   

    */

   

   var geocoder = new Geocoder({

          map: map,

          autoComplete:true,

          arcgisGeocoder:{

            sourceCountry:"US",

            suffix: ", USA"

          }

        }, "search");

        //geocoder.startup();

    //console.log(geocoder);

    geocoder.startup();

   

   

    geocoder.on("select", function(evt){

        console.log(evt);

        map.graphics.clear();

        selAddress = evt.result.name;

        score = evt.result.feature.attributes.score;

        console.log(score);

        var spotlight = map.on("extent-change", function(){

        geom1 = evt.result.feature.geometry;

        geom = esri.geometry.toScreenGeometry(map.extent, map.width, map.height, evt.result.extent);

        var width = geom.xmax - geom.xmin;

        var height = geom.ymin - geom.ymax;

        var max = height;

        if(width > height){

            max = width;

        }

        var margin = '-' + Math.floor(max/2) + 'px 0 0 -' + Math.floor(max/2) + 'px';

        var point = evt.result.feature.geometry;

        var symbol = new SimpleMarkerSymbol().setStyle(

        SimpleMarkerSymbol.STYLE_SQUARE).setColor(

          new Color([255,0,0,0.5])

        );

        var graphic = new Graphic(point, symbol);

        map.graphics.add(graphic);

        dojo.query('.spotlight').addClass('spotlight-active').style({

          width: max + 'px',

          height: max + 'px',

          margin: margin

        });

       dojo.disconnect(spotlight);

       map.infoWindow.destroyDijits();

       getSomeResults(geom1);

      });

    });

   

   

    /************************************************** creating legend ****************************************************/

    function getLegend (serviceName)   {

        urlNew = serviceName + "/"   // url base used to get json request for units, and for legend

        lgdRequestHandle = esriRequest ({           // the legend request handle is recreated here as well

            "url": urlNew + "legend" ,

            "content": {

                "f": "json"

            },

            "callbackParamName": "callback"

        });

        lgdRequestHandle.then(lgdRequestSucceeded, requestFailed);

    }

   

    function lgdRequestSucceeded(response, io) {

        var legendLyrs = arcgisUtils.getLegendLayers(response);

        var lyrs;

        var fieldInfo, pad;

        pad = dojoString.pad;

        for (i=0;i<(response.layers.length);i++){

            if(response.layers.layerId == 3 ){

                lgndDetail={

                    label:"layerName",

                    items:[]

                };

                var tabBody=document.getElementById("tabBody1");

                // once layer name matched with json result, the items from legend json are added, row by row

                for(j=0;j<(response.layers.legend.length);j++){

                    var LayerName = response.layers.layerName;         

                    var imgSource = featureURL + "/" + response.layers.layerId + "/images/" + response.layers.legend.url;

                    var valueSource = response.layers.legend.label;  // used for classifications

                    var imgT = dom.byId("image");

                    addRow(imgSource,valueSource, tabBody);

                    lgndDetail.items.push(lang.mixin({id: response.layers.layerId, layerName: response.layers.layerName}, lang.mixin({label: response.layers.legend.label, img: featureURL + "/" + response.layers.layerId + "/images/" + response.layers.legend.url })));

                } 

                store = new ItemFileReadStore ({data:lgndDetail});

            }

        }

    }

       

     function requestFailed(error, io){

        console.log("failure");

        domClass.add(dom.byId("content"), "failure");

        dojoJson.toJsonIndentStr = " ";

        dom.byId("content").value = dojoJson.toJson(error, true);

    }  

       function addRow(image,value, tbody){

            if (!document.getElementById) return;

            row=document.createElement("tr");

            cell1 = document.createElement("td");

            cell2 = document.createElement("td");

            imgNode1 = document.createElement("img");

            imgNode1.src = image;

            if (value == countyN) {

                imgNode1.style.opacity = 0.80;

            }

            else {

                imgNode1.style.opacity = 0.80;           

            }

            textnode2=document.createTextNode(value);

            cell1.appendChild(imgNode1);

            cell2.appendChild(textnode2);

            row.appendChild(cell1);

            row.appendChild(cell2);

            tbody.appendChild(row);

        }   

   

    /*************************************** linking geocoder with automatic identify *********************************************************/

   

    function getSomePoints(event){

      

       var mapPt = event.mapPoint; 

       getSomeResults(mapPt); 

    }

    function getSomeResults(geom){    

          identifyTask = new IdentifyTask(featureURL);

          identifyParams = new IdentifyParameters();

          identifyParams.tolerance = 3;

          identifyParams.returnGeometry = true;

          identifyParams.layerIds = [2, 3, 4];

          identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;

          identifyParams.width = map.width;

          identifyParams.height = map.height;

          identifyParams.geometry = geom;

          identifyParams.mapExtent = map.extent;

          identifyTask.execute(identifyParams, onIdentifyComplete)

    }

    function onIdentifyComplete(results){

        console.log(results);

        if (results.length > 0){

                    k=0;

                    results.value = "frontier";

                    map.infoWindow.destroyDijits();

                    map.infoWindow.setContent (selAddress + " has a county diversity score of: " + score);

                    map.infoWindow.show(geom1);

                }

                else {

                    map.infoWindow.destroyDijits();

                    map.infoWindow.setContent ("there was a problem connecting to the layer");

                    map.infoWindow.show(geom1);

               } 

    }

   

        function mapReady () {

          map.on("click", executeIdentifyTask);

          identifyTaskClk = new IdentifyTask(featureURL);

          identifyParamsClk = new IdentifyParameters();

          identifyParamsClk.tolerance = 3;

          identifyParamsClk.returnGeometry = true;

          identifyParamsClk.layerIds = [3, 4];

          identifyParamsClk.layerOption = IdentifyParameters.LAYER_OPTION_ALL;

          identifyParamsClk.width = map.width;

          identifyParamsClk.height = map.height;

        }

        /********************************************************** used for hover, with is disabled at this time **********************************************************/

       

        function executeIdentifyTask (event) {

          identifyParamsClk.geometry = event.mapPoint;

          var coordX = identifyParamsClk.geometry.x;

          identifyParamsClk.mapExtent = map.extent;

          var deferred = identifyTaskClk

            .execute(identifyParamsClk)

            .addCallback(function (response) {

                if (response.length == 0){

                    k=0;

                    response.value = "frontier";

                    map.infoWindow.destroyDijits();

                    map.infoWindow.setContent ("This area has no records");

                    map.infoWindow.show(event.mapPoint);

                }

                else {

                    map.infoWindow.destroyDijits();

                    map.infoWindow.setContent ("This area has records");

                    map.infoWindow.show(event.mapPoint);

               } 

            });

           

       

        }

       

      });

    </script>

  </head>

 

  <body>

    <div id="map"

    onclick = "nhpup.popup(hoverLbl)">

   

       <div id="info">

           <div id= "units"></div>

           <table id="legend" border = '1'>

                <tbody id ="tabBody1">

                </tbody>

           </table>

       </div>

   

   

    </div>

   

    <div id="buttons">

        <div id="search"></div> 

    </div>

  </body>

</html>

0 Kudos
KellyHutchins
Esri Frequent Contributor

Ok so I see the issue. If you have autocomplete on and use the suffix then if you choose a suggestion from the list USA will be appended. So with autocomplete enabled its probably best to avoid the suffix.  One option that may work for you is to use the searchExtent to restrict the geocode results. I tested this with your code and it returned the correct results for the DC address.

   var geocoder = new Geocoder({

          map: map,

          autoComplete:true,

          arcgisGeocoder:{

            sourceCountry:"US",

            searchExtent: map.extent

          }

        }, "search");

    geocoder.startup();

DavidMarquardt
New Contributor III

Kelly,

Thanks, this works much better than the other options.  Sure appreciate it,

David

0 Kudos
FilipKrál
Occasional Contributor III

Hello Kelly Hutchins‌ and anyone who made this work,

I have a similar problem. I'm trying to Geocoder widget to search for places in the United Kingdom but the suggestions include results from other countries.

This is how I configured the Geocoder widget:

            // create geocoder widget
            var geocoder = new Geocoder({
              map: map,
              autoComplete: true,
              esriGeocoder: {
                name: "Esri World Geocoder",
                placeholder: "Search places...",
                searchExtent: new geometry.Extent(-10.0, 50.0, 5.0, 62.0, { "wkid": 4326 }),
                sourceCountry: "GBR"
              }
            }, node.attr('id'));

            geocoder.startup();

And this is what I see in the map:

geocoder.png

I tried searchExtent: map.extent too but it made no difference.

I tried adding suffix: ", United Kingdom" but it had no effect either.

Any advice will be much appreciated.

Filip.

0 Kudos
KellyHutchins
Esri Frequent Contributor

Currently to restrict the content that shows up in the suggestions list you need to specify searchExtent. I ran a quick test using code similar to yours and it worked for me. Typing Oxford returned only locations in the UK. Here's a screen shot showing the results and here's the code that works for me. Screen Shot 2015-01-13 at 3.32.37 PM.png

0 Kudos
FilipKrál
Occasional Contributor III

Thank you Kelly,

I've made some progress thanks to your code but the results are still not satisfactory because then it searches for streets instead of towns. Adding property categories: ["City"] seems to help in some way, but then for example while searching for Manchester as "Man", the suggestions were:

  • Manchester, England, United Kingdom
  • Isle of Man, Isle of Man
  • 10 de Mayo, Avenida Manuel Ojinaga, Cuauhtémoc, Chihuahua
  • 10 Pastéis, Avenida Cosme Ferreira, Manaus, Norte

Ideally I would like to get results like

  • Manchester, England, United Kingdom
  • Manchester Rd, Audenshaw, England, United Kingdom
  • Manchester Road, Manchester, England, United Kingdom
  • Manchester Road, ...

In fact the best scenario would if the geocoder searched within the specified extent, cities first, then villages, then streets.

I'll try to figure out more from the js api help‌‌ but if anyone has done this successfully before I'd be glad for any advice.

Many thanks,

Filip.

0 Kudos
DavidMarquardt
New Contributor III

Which version of the javascript api are you using?  My script wasn't working correctly until I switched from 3.11 to 3.12.  ended up referencing:

    <script src="http://js.arcgis.com/3.12/"></script>

0 Kudos
FilipKrál
Occasional Contributor III

The results in my last post were with version 3.12.

Filip.

0 Kudos