custom search completion doesn't replace suggestedResult

01-29-2021 08:11 AM
New Contributor

Hello people,


I am looking for a way to search for a scientific species name and receiving the data from the GBIF api.

Now I have already implemented auto completion if I search for a scientific name, but selecting the name in the search-widget doesn't parse the result to getResults object.

Is there any way to fix this?








<meta charset="utf-8"/>
<title>All birds</title>

#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;

<script src=""></script>
<script src=""></script>


], function (
) {
// *******************************************************
// Custom tile layer class code
// Create a subclass of BaseTileLayer
// *******************************************************

var TintLayer = BaseTileLayer.createSubclass({
properties: {
urlTemplate: null,
tint: {
value: null,
type: Color

// generate the tile url for a given level, row and column
getTileUrl: function (level, row, col) {
return this.urlTemplate
.replace("{z}", level)
.replace("{x}", col)
.replace("{y}", row);

// This method fetches tiles for the specified level and size.
// Override this method to process the data returned from the server.
fetchTile: function (level, row, col, options) {
// call getTileUrl() method to construct the URL to tiles
// for a given level, row and col provided by the LayerView
var url = this.getTileUrl(level, row, col);

// request for tiles based on the generated url
// the signal option ensures that obsolete requests are aborted
return esriRequest(url, {
responseType: "image",
signal: options && options.signal
function (response) {
// when esri request resolves successfully
// get the image from the response
var image =;
var width = this.tileInfo.size[0];
var height = this.tileInfo.size[0];

// create a canvas with 2D rendering context
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;

// Apply the tint color provided by
// by the application to the canvas
if (this.tint) {
// Get a CSS color string in rgba form
// representing the tint Color instance.
context.fillStyle = this.tint.toCss();
context.fillRect(0, 0, width, height);

// Applies "difference" blending operation between canvas
// and steman tiles. Difference blending operation subtracts
// the bottom layer (canvas) from the top layer (tiles) or the
// other way round to always get a positive value.
context.globalCompositeOperation = "difference";

// Draw the blended image onto the canvas.
context.drawImage(image, 0, 0, width, height);

return canvas;

// *******************************************************
// Start of JavaScript application
// *******************************************************

// Create a new instance of the TintLayer and set its properties
var stamenTileLayer = new TintLayer({

title: "All birds"

var url = ""
var suffix = "&rank=species"

var customSearchSource = new SearchSource(
placeholder: "Enter Scientific name",
getSuggestions: function (params) {
// Make a custom url for the esri request
let customUrl = url + params.suggestTerm.replace(/ /g, "%20") + suffix;
var options = {
query: {
f: "json"
responseType: "json"

return esriRequest(customUrl, options).then
function (results) {
// Return the scientific names
return (feature) {
key: "name",
text: feature.species,
// Note: add whatever field you require (i.e. 'canonicalName', 'species', 'genus', etc.)
speciesKey: feature.speciesKey
getResults: function(params) {
// The selected result are stored in the params.suggestResult object
console.log('Selected result: ', params);
console.log('Species: ', params.suggestResult.text);
console.log('Species key: ', params.suggestResult.speciesKey);

/* FIXME: when clicking a species, it will show:
* 'No results found for <selected species>'
* This is because the search action searches the layer data.

// TODO: add logic for retrieving new data and updating the layer
// ...

// add the new instance of the custom tile layer
var map = new Map({
basemap: "topo-vector",
layers: [stamenTileLayer]

// create a new scene view and add the map
var view = new MapView({
container: "viewDiv",
map: map,
center: [6.5665018, 53.2193835],
zoom: 11

// create a layer list widget
var layerList = new LayerList({
view: view

// Create a SearchWidget
// Note: added a few settings, all optional.
const searchWidget = new Search(
view: view,
sources: [customSearchSource],
includeDefaultSources: false,
autoSelect: false,
locationEnabled: false,
minSuggestCharacters: 3,
searchAllEnabled: false,
suggestionDelay: 300

view.ui.add(layerList, "top-right");
view.ui.add(searchWidget, "top-right");

/* Add events -after- the search has been added to the view */
searchWidget.viewModel.on("search-complete", function(event){
// The results are stored in the event Object[]
// Note: missing species key
console.log("Selected species: ", event.searchTerm);
// TODO: add logic for retrieving new data and updating the layer


<div id="viewDiv"></div>



Tags (3)
0 Kudos
2 Replies
by Anonymous User
Not applicable

I realized I was looking at the properties of Layersource so I deleted my previous suggestion of using displayName. 

Using your code in a code pen, I think you need to change a few parameters.

key: "species",
text: feature.species,
sourceIndex: feature.speciesKey

This doesn't produce the not found error, and keeps the typed value and watching the example, the selected name gets populated only after the subsequent query runs.  To get the selection to populate the box, I think you will need to work out your getResults code and return the object.

Hope this helps.

New Contributor

Hi JeffK, thanks for your reply! I'm going to go at it using your suggestions 🙏

0 Kudos