Struggling to populate FilteringSelect in my custom widget

1757
3
Jump to solution
03-21-2014 12:27 PM
JohnCorrea
New Contributor
Hello all,

I'm trying to create a widget that filters down options based on attributes. This widget isn't near completion because I cannot get the first item to populate. As you all know, you cannot reference your nodes using byId() when you're referencing a template mixin but rather reference it by using this.data-dojo-attach-point_name. I am doing just that and seem to be able to add child option nodes to my FilteringSelect drop down menu but only outside the queryTask.execute() function within the postCreate function. Somehow the reference to my FilteringSelect element gets lost when entering the function call within queryTask.execute(query, addItem) and nothing gets added. I've highlighted in green what seems to work and then highlighted in red what doesn't. Can someone please share a way that I can actually reference the attach-point of my FilteringSelect and add children to it within the scope of the execute function? Help would be appreciated.



----- template -------
<div>
<label>County:</label>
<br>
<select data-dojo-type="dijit/form/FilteringSelect" data-dojo-attach-point="fsCounty" >
</select>
<br>
<label>Township:</label>
<br>
<select data-dojo-type="dijit/form/FilteringSelect" data-dojo-attach-point="fsTownship">
</select>
</div>
--------------------

require([
"dojo/_base/declare", "dojo/_base/array", "dojo/dom", "dojo/dom-construct", "dojo/parser", "dojo/ready", "dojo/data/ItemFileReadStore",
"dijit/_WidgetBase", "dijit/_TemplatedMixin", "dojo/text!./widget/template/SearchFormTemplate.html",
"esri/layers/FeatureLayer", "esri/tasks/query", "esri/tasks/QueryTask", "dijit/form/FilteringSelect"
], function( declare, array, dom, domConstruct, parser, ready, ItemFileReadStore, _WidgetBase, TemplatedMixin, template, FeatureLayer, Query, QueryTask ){

declare( "AttributeFilter", [_WidgetBase, TemplatedMixin ], {

templateString: template,

options: {
theme: "nihilo"
},

_map: null,
_layer: "http://services..............",
_criteria1: "COUNTY",
_criteria2: "NAME",
_countyOptionArray: null,
_selectorOne: null,

constructor: function(){

this._countyOptionArray = new Array();

},
postCreate: function() {

var query = new Query();
query.outFields = [this._criteria1];
query.where = "COUNTY IS NOT NULL";
query.returnGeometry = false;

var queryTask = new QueryTask(this._layer);

var fsCounty = this.fsCounty;

var option = document.createElement("option");
option.text = "Select a County";

fsCounty.add(option);


queryTask.execute(query, function(results){

var zone;
var values = [];
var testVals = {};

var features = results.features;
array.forEach(features, function (feature) {

zone = feature.attributes.COUNTY;

if (!testVals[zone]) {
testVals[zone] = true;
values.push({ name: zone });
}
});


//ComboBox's data source
var dataItems = {
identifier: 'name',
label: 'name',
items: values
};

array.forEach(dataItems.items, addItem );

});

function addItem(item){

var option = document.createElement("option");
option.text = item.name;
option.value = item.name;

console.log(option.text);

fsCounty.add(option);


}
},
setMap: function (m){
this._map = m;
},

selectPopulate: function(){

},
selectZoom: function(){

}

});

ready(function(){

parser.parse();
});

});
0 Kudos
1 Solution

Accepted Solutions
JohnGrayson
Esri Regular Contributor
What I normally do in dojo classes and dijits to maintain scope is to make sure I use lang.hitch(...) for my inline or referenced methods. That way I can access the data-dojo-attach-point members directly.  Here's a rough example:

queryTask.execute(query, lang.hitch(this,postResults));


Then, inside of postResults you can access the members like so:

this.fsCounty.set("store", store);

View solution in original post

3 Replies
TracySchloss
Frequent Contributor
I don't know if you can make use of how I did mine, but I needed to do something similar.  I had a township layer and I needed to generate a drop down list with all the choices, using a filteringselect.  I think you are better off first creating an array to hold all your selections and then using that to populate a Memory and then define that as the store to your filteringSelect.

First I keep all my tool in a right hand pane inside titlePane's so the location of the filteringSelect looks like this:

       <div id="tp_twpSearch" data-dojo-type="dijit/TitlePane" 
       data-dojo-props="title:'Find Township / Range', closable:false, open:false">
       <div id="searchDiv">
         <select id="pickSelect" data-dojo-type="dijit/form/FilteringSelect"  placeHolder="Select a township"
         data-dojo-props="title:'Find points in selected township/range',maxHeight:200, size: 30, queryExpr:'${0}*', ignoreCase:true">        
     </select>
       </div>
   </div> 


Since I figured I might want to use this functionality later, I made a function that would accept a layer name and the field it needed to use.  This is executed on map load.

populateDropDownList(twpRngLayer, "LABEL_1");

These are the functions that run the query and populate the dropdown.  You'll need to make sure to have all the appropriate requires defined.
//Populates pick list
function populateDropDownList(dropdownLayer, pickField){
    pickAttr = pickField;
    pickLayer = dropdownLayer;
    var queryTask = new QueryTask(pickLayer.url + "/0");
    var query = new Query();
  query.outFields = [pickField];
    query.where = "1=1";
    query.returnGeometry = false;  
    query.outSpatialReference = spatialReference;
    queryTask.on('complete', populateResultsHandler);
    queryTask.on('error', errorHandler);
    queryTask.execute(query);
}
function errorHandler(err){
    console.log("Error executing queryTask: " + err.details);
}
    
function populateResultsHandler(results){
    var select = registry.byId("pickSelect");//my filteringSelect dijit
    pickList.length = 0;
    var numResults = results.featureSet.features.length;
      for (var j = 0; j < numResults; j++) {
          var pickCode = results.featureSet.features.attributes[pickAttr];
        pickList.push({id: pickCode, label: pickCode});
      }
      pickList.sort(function(item1, item2) {
        var label1 = item1.label.toLowerCase(),
        label2 = item2.label.toLowerCase();      
        return (label1 > label2) ? 1 : (label1 < label2) ? -1 : 0;
    });

   var dataStore = new Memory({data:pickList, idProperty:"id"});
    select.set ("searchAttr", "id");
    select.set("labelAttr", "id");
    select.set("store", dataStore);
}
0 Kudos
JohnCorrea
New Contributor
Tracy you were right by giving the dijit/registry suggestion. However, for some reason you have to give the module a global reference to the dojo-data-attach-point node that use use in your template and then you have to assign it an id. I've boldened to crucial points. Thanks for the help.


require([
    "dojo/_base/declare", "dojo/_base/array", "dojo/dom", "dojo/dom-construct", "dojo/parser", "dojo/ready", "dojo/data/ItemFileReadStore",
    "dijit/_WidgetBase", "dijit/_TemplatedMixin", "dijit/registry", "dojo/text!./template/SearchFormTemplate.html",
    "esri/layers/FeatureLayer", "esri/tasks/query", "esri/tasks/QueryTask", "dijit/form/FilteringSelect"
], function (declare, array, dom, domConstruct, parser, ready, ItemFileReadStore, _WidgetBase, TemplatedMixin, registry, template, FeatureLayer, Query, QueryTask) {

    declare("AttributeFilter", [_WidgetBase, TemplatedMixin ], {

        templateString: template,

        options: {
            theme: "nihilo"
        },

        _map: null,
        _layer: "http://services.femadata.com/arcgis/rest/services/FEMA_R8/Dakotas_PLSS/FeatureServer/1",
        _criteria1: "COUNTY",
        _criteria2: "NAME",
        _store1: null,
        _selectorOne: null,

        constructor: function () {},
        postCreate: function () {

            var fsCounty = this.fsCounty;
            this._selectorOne = this.fsCounty;
            this._selectorOne.id = "fsCounty";


            var query = new Query();
            query.outFields = [this._criteria1];
            query.where = "COUNTY IS NOT NULL";
            query.returnGeometry = false;

            var queryTask = new QueryTask(this._layer);

            queryTask.execute(query, postResults);

            function postResults(results) {

                var zone;
                var values = [];
                var testVals = {};

                var features = results.features;
                array.forEach(features, function (feature) {

                    zone = feature.attributes.COUNTY;

                    if (!testVals[zone]) {
                        testVals[zone] = true;
                        values.push({ name: zone });
                    }
                });

                var dataItems = {
                    identifier: 'name',
                    label: 'name',
                    items: values
                };

                var store = new ItemFileReadStore({data: dataItems});
                registry.byId("fsCounty").set("store", store);
            }
        },
        setMap: function (m) {
            this._map = m;
        },
        selectPopulate: function () {},
        selectZoom: function () {}
    });

    ready(function () {

        parser.parse();
    });

});
0 Kudos
JohnGrayson
Esri Regular Contributor
What I normally do in dojo classes and dijits to maintain scope is to make sure I use lang.hitch(...) for my inline or referenced methods. That way I can access the data-dojo-attach-point members directly.  Here's a rough example:

queryTask.execute(query, lang.hitch(this,postResults));


Then, inside of postResults you can access the members like so:

this.fsCounty.set("store", store);