Skip to content

Instantly share code, notes, and snippets.

@odoe
Created October 16, 2014 17:47
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save odoe/c35958b605d789aba189 to your computer and use it in GitHub Desktop.
AutoComplete EsriJS search widget
define([
'dojo/_base/declare',
'dojo/_base/lang',
'dojo/Deferred',
'esri/tasks/locator'
], function(
declare, lang,
Deferred,
Locator
) {
'use strict';
function asAddress(params, val) {
var address
, options;
address = {
'SingleLine': val
};
options = {
address: address,
outFields: params.outFields
};
return options;
}
return declare(null, {
constructor: function(options, spatialReference) {
this.options = options || {};
this.params = options.params;
this.spatialReference = spatialReference;
this.url = this.options.url;
this.task = new Locator(this.url);
this.task.outSpatialReference = this.spatialReference;
},
execute: function(val) {
if (val.length < 5) {
var deferred = new Deferred();
setTimeout(function() {
deferred.resolve([]);
}, 100);
return deferred.promise;
} else {
return this.task.addressToLocations(asAddress(this.params, val));
}
}
});
});
define([
'dojo/_base/declare',
'dojo/_base/lang',
'dojo/_base/array',
'dojo/dom',
'dojo/dom-construct',
'dojo/dom-attr',
'dojo/dom-class',
'dojo/on',
'dojo/topic',
'dojo/query',
'dojo/Evented',
// Dijit stuff
'dijit/_WidgetBase',
'dijit/_TemplatedMixin',
'dijit/a11yclick',
'esri/graphicsUtils',
'utils/symbolutil',
// widget tools
'widgets/agssearch/services/searchservice',
// template
'text!widgets/agssearch/templates/agssearch.tpl.html'
], function(
declare, lang, arrayUtil,
dom, domConstruct, domAttr, domClass,
on, topic, query,
Evented,
_WidgetBase, _TemplatedMixin, a11yclick,
graphicsUtils,
symbolUtil,
SearchService,
template
) {
'use strict';
function stopEvent(e) {
e.preventDefault();
}
function val(t, name) {
return t[name];
}
function domval(name) {
return val(dom.byId(name), 'value');
}
function head(t) {
if (t && lang.isArray(t)) {
return t[0];
} else {
return {};
}
}
return declare([_WidgetBase, _TemplatedMixin, Evented], {
templateString: template,
// lifecycle 1
constructor: function() {
this.searchCount = 0;
this.loaded = false;
this.findPlaceHolder = 'Find...';
},
// start widget
startup: function() {
this._init();
},
postCreate: function() {
this._findService = new SearchService({
map: this.get('map'),
settings: this.get('settings')
});
this.own(
on(dom.byId('searchForm'), 'submit', stopEvent),
on(dom.byId('searchForm'), 'keyup', lang.hitch(this, '_find')),
on(dom.byId('find-clear'), a11yclick, lang.hitch(this, '_clearSearch')),
on(
document.body,
'.find-result:click',
lang.hitch(this, '_itemClicked')
)
);
},
_itemClicked: function(e) {
var term
, value
, cache
, found
, fieldName;
term = domAttr.get(e.target, 'data-term');
value = domAttr.get(e.target, 'data-lookup');
cache = head(this._findService.store.query({
term: term
}));
fieldName = this.get('searchField');
dom.byId('find-input').value = value;
this._clear();
found = head(arrayUtil.filter(cache.results, function(item) {
if (item.value && item.value === value) {
return item.value === value;
}
if (item.feature.attributes[fieldName] === value) {
return item.feature.attributes[fieldName] === value;
}
return false;
}));
if (found && found.feature && found.feature.geometry) {
this.map.graphics.clear();
if (!found.feature.symbol) {
if (found.feature.geometry.type === 'polygon') {
found.feature.setSymbol(symbolUtil.selectedPolygonSymbol());
} else if (found.feature.geometry.type === 'point') {
found.feature.setSymbol(symbolUtil.locationMarker());
}
}
this.map.graphics.add(found.feature);
if (found.feature.geometry.type !== 'point') {
this.map.setExtent(graphicsUtils.graphicsExtent([found.feature]));
} else {
this.map.centerAndZoom(
found.feature.geometry,
this.map._params.lods.length - 2
);
}
}
},
// widget methods
_updateList: function(response) {
var list
, elems
, fieldName;
list = dom.byId('resultsList');
fieldName = this.get('searchField');
this._clear();
elems = arrayUtil.map(response.results, function(item) {
if (item.value) {
return [
'<li value="',
item.value,
'"',
' data-lookup="',
item.value,
'"',
' data-term="',
response.term,
'"',
' class="find-result">',
item.foundFieldName ?
[item.foundFieldName, ' - ', item.value].join('') : item.value,
'</li>'
].join('');
} else {
return [
'<li value="',
item.feature.attributes[fieldName],
'"',
' data-term="',
response.term,
'"',
' class="find-result">',
item.feature.attributes[fieldName],
'</li>'
].join('');
}
});
list.innerHTML = elems.join('');
domClass.remove(dom.byId('findResults'), 'hidden');
if (!--this.searchCount) {
domClass.remove(dom.byId('find-input'), 'ags-searching');
this.emit('search-complete', {});
}
},
_clear: function() {
domClass.add(dom.byId('findResults'), 'hidden');
domClass.remove(dom.byId('find-input'), 'ags-searching');
domConstruct.empty(dom.byId('resultsList'));
},
_clearSearch: function() {
this._clear();
dom.byId('find-input').value = '';
this.map.graphics.clear();
},
_find: function() {
this.search(domval('find-input'));
},
search: function(term) {
if (term.length > 2) {
this.searchCount++;
domClass.add(dom.byId('find-input'), 'ags-searching');
this.emit('search-start', {});
this._findService.search(term).then(
lang.hitch(this, '_updateList'),
lang.hitch(this, function() { this.searchCount--; })
);
} else {
this._clear();
}
},
// private functions
_init: function() {
this.set('loaded', true);
}
});
});
@searching: #FFFF00;
#findDiv {
position: absolute;
top: 10px;
right: 10px;
z-index: 50;
}
#searchForm {
float: left;
height: 30px;
margin-left: 10px;
margin-right: 15px;
width: 250px;
input {
float: right;
height: 30px !important;
}
}
#find-clear {
float: right;
margin-top: 5px;
cursor: pointer;
}
.ags-searching {
background-color: @searching;
}
#findResults {
padding: 2px;
margin-top: 32px;
background-color: #fff;
color: #000;
li {
list-style-type: none;
padding: 5px;
cursor: pointer;
}
}
<div id="findDiv">
<form id="searchForm" role="form">
<input id="find-input" class="form-control"
placeholder="${findPlaceHolder}"
title="${findPlaceHolder}"
type="text" value="">
<div id="findResults" class="hidden">
<ul id="resultsList"></ul>
</div>
</form>
<span id="find-clear" class="glyphicon glyphicon-remove"></span>
</div>
define([], {
return {
"name": "agssearch",
"path": "widgets/agssearch/agssearch",
"node": "findDiv",
"nodeVisible": true,
"options": {
"searchField": "AIN",
"settings": {
"searchparams": [{
"url": "<MAPSERVER URL>",
"type": "query",
"searchField": "AIN",
"params": {
"returnGeometry": true,
"outFields": [ "OBJECTID", "AIN" ]
}
}, {
"url": "<MAPSERVER URL>",
"type": "find",
"params": {
"layerIds": [0],
"returnGeometry": true,
"searchFields": ["ID", "LOC_ID", "LOCATION"],
"outFields": [ "ID", "LOC_ID", "LOCATION" ]
}
}, {
"url": "<LOCATOR SERVICE URL>",
"type": "address",
"params": {
"outFields": [ "Loc_name" ]
}
}]
}
}
};
});
define([
'dojo/_base/declare',
'dojo/_base/lang',
'esri/tasks/FindTask',
'esri/tasks/FindParameters'
], function(
declare, lang,
FindTask, FindParameters
) {
'use strict';
function paramsGen(params) {
return lang.mixin(new FindParameters(), params);
}
function withSearch(params, val) {
params.searchText = val;
return params;
}
return declare([], {
constructor: function(options) {
this.options = options || {};
this.url = this.options.url;
this.task = new FindTask(this.url);
this.params = paramsGen(options.params);
},
execute: function(val) {
return this.task.execute(withSearch(this.params, val));
}
});
});
define([
'dojo/_base/declare',
'dojo/_base/lang',
'esri/tasks/QueryTask',
'esri/tasks/query'
], function(
declare, lang,
QueryTask, Query
) {
'use strict';
function paramsGen(params) {
return lang.mixin(new Query(), params);
}
return declare(null, {
constructor: function(options) {
this.options = options || {};
this.url = this.options.url;
this.task = new QueryTask(this.url);
this.params = paramsGen(options.params);
},
execute: function(val) {
this.params.where = [
this.options.searchField,
" LIKE '%",
val,
"%'"
].join('');
return this.task.execute(this.params);
}
});
});
define([
'dojo/_base/declare',
'dojo/_base/lang',
'dojo/_base/array',
'dojo/Deferred',
'dojo/promise/all',
'dojo/store/Memory',
'esri/graphic',
'./findservice',
'./queryservice',
'./addressservice'
], function(
declare, lang, arrayUtil,
Deferred, all,
Memory,
Graphic,
FindService, QueryService, AddressService
) {
'use strict';
function head(t) {
return t[0];
}
function concat(arr1, arr2) {
return [].concat(arr1, arr2);
}
function top(arr, num) {
return arr.slice(0, num);
}
function assign(items) {
return arrayUtil.map(items, function(item) {
return {
feature: item
};
});
}
function isAddress(item) {
return !!item.address;
}
function transform(item) {
return {
feature: new Graphic(item.location, null, item.attributes),
value: item.address
};
}
function filterAddressesByScore(arr, score) {
return arrayUtil.filter(arr, function(address) {
return address.score > score;
});
}
function validateArray(arr) {
if (head(arr) && isAddress(head(arr))) {
return arrayUtil.map(top(filterAddressesByScore(arr, 75), 10), transform);
} else {
return arr;
}
}
function cleanResults(results) {
var clean = [];
arrayUtil.forEach(results, function(res) {
if (lang.isArray(res)) {
clean = concat(clean, validateArray(res));
} else {
clean.push(res);
}
});
return clean;
}
function clean(results) {
var features = [];
arrayUtil.forEach(cleanResults(results), function(result) {
if (result.features) {
features = concat(features, assign(top(result.features, 10)));
} else {
features.push(result);
}
});
return features;
}
return declare(null, {
options: {},
constructor: function(options) {
var sr;
this.options = options || {};
this.store = new Memory({
data: [],
idProperty: 'term'
});
this.tasks = [];
sr = this.options.map.spatialReference;
if (this.options.settings.searchparams) {
var sparams = this.options.settings.searchparams;
this.tasks = arrayUtil.map(sparams, function(param) {
if (param.type === 'query') {
return new QueryService(param);
} else if (param.type === 'find') {
return new FindService(param);
} else if (param.type === 'address') {
return new AddressService(param, sr);
}
}, this);
}
},
search: function(term) {
var def, promises, cache;
def = new Deferred();
cache = this.store.get(term);
if (cache) {
def.resolve({
results: cache.results,
term: term
});
} else {
promises = arrayUtil.map(this.tasks, function(task) {
return task.execute(term);
});
all(promises).then(lang.hitch(this, function(results) {
var res = clean(results);
this.store.add({
term: term,
results: res
});
def.resolve({
results: res,
term: term
});
}));
}
return def.promise;
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment