I'm having trouble adding a loading icon to this app. I want it to appear when the user makes a query. In the map, the points change to whatever category or item_keyword the user selects from the two drop-downs. As it stands, after making a selection the user can't tell when the process completes.
I'm able to display a loading icon for the map view as this example demonstrates, but I'm not sure how to do it on a query.
Here's the section of my app dealing with queries:
// query all features from the recycle layer
view
.when(function () {
return recycleLayer.when(function () {
var query = recycleLayer.createQuery();
return recycleLayer.queryFeatures(query);
});
})
.then(getValues)
.then(getUniqueValues)
.then(addToSelect);
// re-query the layer based on the selected Category and re-populate the keyword select
catTypeSelect.addEventListener("change", function () {
var sqlExp = "";
if (catTypeSelect.selectedIndex > 0) {
sqlExp +=
"Category LIKE '%" +
catTypeSelect.options[catTypeSelect.selectedIndex].value +
"%'";
}
var query = recycleLayer.createQuery();
query.where = sqlExp;
recycleLayer
.queryFeatures(query)
.then(getValues2)
.then(getUniqueValues2)
.then(addToSelect2);
setDefinitionExpression();
});
keyTypeSelect.addEventListener("change", setDefinitionExpression);
// return an array of all the values in the
// Category and item_keyword fields of the Recycle layer
function getValues(response) {
var features = response.features;
var values = features.map(function (feature) {
return {
Category: feature.attributes.Category,
item_keyword: feature.attributes.item_keyword
};
});
return values;
}
// re-query the layer based on the selected Category and re-populate the keyword select
function getValues2(response) {
var features = response.features;
var values = features.map(function (feature) {
return feature.attributes.item_keyword;
});
return values;
}
// return an array of unique values in
// the item_keyword and Category fields of the Recycle layer
function getUniqueValues(values) {
var uniqueKeyValues = [];
var uniqueCatValues = [];
values.forEach(function (item, i) {
var keyVal = item.item_keyword.split(";");
var catVal = item.Category.split(";");
catVal.map(function (val1) {
if (
(uniqueCatValues.length < 1 ||
uniqueCatValues.indexOf(val1) === -1) &&
val1 !== ""
) {
uniqueCatValues.push(val1);
}
});
keyVal.map(function (val2) {
if (
(uniqueKeyValues.length < 1 ||
uniqueKeyValues.indexOf(val2) === -1) &&
val2 !== ""
) {
uniqueKeyValues.push(val2);
}
});
});
return {
uKeyVals: uniqueKeyValues,
uCatVals: uniqueCatValues
};
}
// re-query the layer based on the selected Category and re-populate the keyword select
function getUniqueValues2(values) {
var uniqueKeyValues = [];
values.forEach(function (item, i) {
var keyVal = item.split(";");
keyVal.map(function (val2) {
if (
(uniqueKeyValues.length < 1 ||
uniqueKeyValues.indexOf(val2) === -1) &&
val2 !== ""
) {
uniqueKeyValues.push(val2);
}
});
});
return uniqueKeyValues;
}
// Add the unique values to the recycle type
// select element. This will allow the user
// to filter categories by type.
function addToSelect(values) {
var dOpt = document.createElement("option");
dOpt.value = "";
dOpt.selected = true;
dOpt.text = "Select one";
catTypeSelect.add(dOpt);
values.uCatVals.sort();
values.uCatVals.forEach(function (value) {
var option = document.createElement("option");
option.text = value;
catTypeSelect.add(option);
});
var dOpt2 = document.createElement("option");
dOpt2.value = "";
dOpt2.selected = true;
dOpt2.text = "Select one";
keyTypeSelect.add(dOpt2);
values.uKeyVals.sort();
values.uKeyVals.forEach(function (value) {
var option = document.createElement("option");
option.text = value;
keyTypeSelect.add(option);
});
return setDefinitionExpression();
}
// re-query the layer based on the selected Category and re-populate the keyword select
function addToSelect2(values) {
while (keyTypeSelect.options.length > 0) {
keyTypeSelect.remove(0);
}
var dOpt2 = document.createElement("option");
dOpt2.value = "";
dOpt2.disabled = true;
dOpt2.selected = true;
dOpt2.text = "Select one";
keyTypeSelect.add(dOpt2);
values.sort();
values.forEach(function (value) {
var option = document.createElement("option");
option.text = value;
keyTypeSelect.add(option);
});
return true;
}
// set the definition expression on the recycle
// layer to reflect the selection of the user
function setDefinitionExpression() {
var sqlExp = "";
if (catTypeSelect.selectedIndex > 0) {
sqlExp +=
"Category LIKE '%" +
catTypeSelect.options[catTypeSelect.selectedIndex].value +
"%'";
}
if (keyTypeSelect.selectedIndex > 0) {
if (sqlExp === "") {
sqlExp +=
"item_keyword LIKE '%" +
keyTypeSelect.options[keyTypeSelect.selectedIndex].value +
"%'";
} else {
sqlExp +=
" AND item_keyword LIKE '%" +
keyTypeSelect.options[keyTypeSelect.selectedIndex].value +
"%'";
}
}
if (resRb.checked) {
if (sqlExp !== "") {
sqlExp += " AND USER_IsRes = 'TRUE'";
}
} else {
if (sqlExp !== "") {
sqlExp += " AND USER_IsBus = 'TRUE'";
}
}
console.info(sqlExp);
recycleLayer.definitionExpression = sqlExp;
if (!recycleLayer.visible) {
recycleLayer.visible = true;
}
return queryForGeometries();
}
// Get all the geometries of the recycle layer
// the createQuery() method creates a query
// object that respects the definitionExpression
// of the layer
function queryForGeometries() {
console.log("Running query");
var rQuery = recycleLayer.createQuery();
return recycleLayer.queryFeatures(rQuery).then(function (response) {
rGeometries = response.features.map(function (feature) {
return feature.geometry;
});
return rGeometries;
});
}
filterButton.addEventListener("click", function () {
setDefinitionExpression();
});
});
Solved! Go to Solution.
No there isn't. Just simply add the
domClass.add('loadingDiv', 'visible');
before
recycleLayer
.queryFeatures(query)
...
and remove it in the addToSelect2 method as I mentioned before.
Jared,
You show the div when you right before you execute the query.
domClass.add('loadingDiv', 'visible'); and then in your results function (the last one addToSelect2) you hide it.
Thanks Robert,
It's apparently a pretty simple operation, but where exactly to put this stuff is not really popping out at me. Is there not an example somewhere?
No there isn't. Just simply add the
domClass.add('loadingDiv', 'visible');
before
recycleLayer
.queryFeatures(query)
...
and remove it in the addToSelect2 method as I mentioned before.
Thanks!
For posterity:
var query = recycleLayer.createQuery();
query.where = sqlExp;
domClass.add('loadingDiv', 'visible'); //add loadingDiv here
recycleLayer
.queryFeatures(query)
.then(getValues2)
.then(getUniqueValues2)
.then(addToSelect2);
select
function addToSelect2(values) {
while (keyTypeSelect.options.length > 0) {
keyTypeSelect.remove(0);
domClass.remove('loadingDiv', 'visible'); //remove loadingDiv here
}
Robert,
Sorry to drag you back into this one. I was wondering how to get the loading div to show when you query both the Category and item_keyword? Right now, the div shows for the Category only.
Jared,
Can you post your full code so I can see what you have done?
// query all features from the recycle layer
view
.when(function () {
return recycleLayer.when(function () {
var query = recycleLayer.createQuery();
return recycleLayer.queryFeatures(query);
});
})
.then(getValues)
.then(getUniqueValues)
.then(addToSelect);
// re-query the layer based on the selected Category and re-populate the keyword select
catTypeSelect.addEventListener("change", function () {
var sqlExp = "";
if (catTypeSelect.selectedIndex > 0) {
sqlExp +=
"Category LIKE '%" +
catTypeSelect.options[catTypeSelect.selectedIndex].value +
"%'";
}
var query = recycleLayer.createQuery();
query.where = sqlExp;
domClass.add('loadingDiv', 'visible'); //add loadingDiv
recycleLayer
.queryFeatures(query)
.then(getValues2)
.then(getUniqueValues2)
.then(addToSelect2);
setDefinitionExpression();
});
keyTypeSelect.addEventListener("change", setDefinitionExpression);
// return an array of all the values in the
// Category and item_keyword fields of the Recycle layer
function getValues(response) {
var features = response.features;
var values = features.map(function (feature) {
return {
Category: feature.attributes.Category,
item_keyword: feature.attributes.item_keyword
};
});
return values;
}
// re-query the layer based on the selected item_keyword and re-populate the keyword select
function getValues2(response) {
var features = response.features;
var values = features.map(function (feature) {
return feature.attributes.item_keyword;
});
return values;
}
// return an array of unique values in
// the item_keyword and Category fields of the Recycle layer
function getUniqueValues(values) {
var uniqueKeyValues = [];
var uniqueCatValues = [];
values.forEach(function (item, i) {
var keyVal = item.item_keyword.split(";");
var catVal = item.Category.split(";");
catVal.map(function (val1) {
if (
(uniqueCatValues.length < 1 ||
uniqueCatValues.indexOf(val1) === -1) &&
val1 !== ""
) {
uniqueCatValues.push(val1);
}
});
keyVal.map(function (val2) {
if (
(uniqueKeyValues.length < 1 ||
uniqueKeyValues.indexOf(val2) === -1) &&
val2 !== ""
) {
uniqueKeyValues.push(val2);
}
});
});
return {
uKeyVals: uniqueKeyValues,
uCatVals: uniqueCatValues
};
}
// re-query the layer based on the selected Category and re-populate the keyword select
function getUniqueValues2(values) {
var uniqueKeyValues = [];
values.forEach(function (item, i) {
var keyVal = item.split(";");
keyVal.map(function (val2) {
if (
(uniqueKeyValues.length < 1 ||
uniqueKeyValues.indexOf(val2) === -1) &&
val2 !== ""
) {
uniqueKeyValues.push(val2);
}
});
});
return uniqueKeyValues;
}
// Add the unique values to the recycle type
// select element. This will allow the user
// to filter categories by type.
function addToSelect(values) {
var dOpt = document.createElement("option");
dOpt.value = "";
dOpt.selected = true;
dOpt.text = "Select one";
catTypeSelect.add(dOpt);
values.uCatVals.sort();
values.uCatVals.forEach(function (value) {
var option = document.createElement("option");
option.text = value;
catTypeSelect.add(option);
});
var dOpt2 = document.createElement("option");
dOpt2.value = "";
dOpt2.selected = true;
dOpt2.text = "Select one";
keyTypeSelect.add(dOpt2);
values.uKeyVals.sort();
values.uKeyVals.forEach(function (value) {
var option = document.createElement("option");
option.text = value;
keyTypeSelect.add(option);
});
return setDefinitionExpression();
}
// re-query the layer based on the selected Category and re-populate the keyword select
function addToSelect2(values) {
while (keyTypeSelect.options.length > 0) {
keyTypeSelect.remove(0);
}
domClass.remove('loadingDiv', 'visible'); //remove loadingDiv
var dOpt2 = document.createElement("option");
dOpt2.value = "";
dOpt2.disabled = true;
dOpt2.selected = true;
dOpt2.text = "Select one";
keyTypeSelect.add(dOpt2);
values.sort();
values.forEach(function (value)
{
var option = document.createElement("option");
option.text = value;
keyTypeSelect.add(option);
});
return true;
}
// set the definition expression on the recycle
// layer to reflect the selection of the user
function setDefinitionExpression() {
var sqlExp = "";
if (catTypeSelect.selectedIndex > 0) {
sqlExp +=
"Category LIKE '%" +
catTypeSelect.options[catTypeSelect.selectedIndex].value +
"%'";
}
if (keyTypeSelect.selectedIndex > 0) {
if (sqlExp === "") {
sqlExp +=
"item_keyword LIKE '%" +
keyTypeSelect.options[keyTypeSelect.selectedIndex].value +
"%'";
} else {
sqlExp +=
" AND item_keyword LIKE '%" +
keyTypeSelect.options[keyTypeSelect.selectedIndex].value +
"%'";
}
}
if (resRb.checked) {
if (sqlExp !== "") {
sqlExp += " AND USER_IsRes = 'TRUE'";
}
} else {
if (sqlExp !== "") {
sqlExp += " AND USER_IsBus = 'TRUE'";
}
}
console.info(sqlExp);
recycleLayer.definitionExpression = sqlExp;
if (!recycleLayer.visible) {
recycleLayer.visible = true;
}
return queryForGeometries();
}
// Get all the geometries of the recycle layer
// the createQuery() method creates a query
// object that respects the definitionExpression
// of the layer
function queryForGeometries() {
console.log("Running query");
var rQuery = recycleLayer.createQuery();
return recycleLayer.queryFeatures(rQuery).then(function (response) {
rGeometries = response.features.map(function (feature) {
return feature.geometry;
});
return rGeometries;
});
}
filterButton.addEventListener("click", function () {
setDefinitionExpression();
});
});
function setDefinitionExpression() {
domClass.add('loadingDiv', 'visible'); //add loadingDiv
...
function queryForGeometries() {
console.log("Running query");
var rQuery = recycleLayer.createQuery();
return recycleLayer.queryFeatures(rQuery).then(function (response) {
rGeometries = response.features.map(function (feature) {
return feature.geometry;
});
domClass.remove('loadingDiv', 'visible'); //remove loadingDiv
return rGeometries;
});
}
Perfect. Thanks a lot.