This sample demonstrates how query features that are visible with the current extent of the view. Census tract names of the features visible within the view's extent are displayed in the calcite-list-item component. When user clicks a tract name in the list, the map zooms to the corresponding tract feature and opens its popup.
The sample uses a FeatureLayer created from a portalItem pointing to a feature service containing 5-year estimates of current marital status by census tract.
It leverages the FeatureLayerView.queryFeatures() method to query features already available for drawing on the client-side, avoiding additional network requests. A Feature is created when a Feature is added to a Map or a Scene, and provides methods and properties to query, filter, and highlight features currently visible in the view.
How it works
The Feature is created from a portalItem with a configured popupTemplate. The layer's outFields property is set to include all fields used by popup and client-side queries. This ensures the required attributes are available on the feature layer view, improving performance and preventing extra server requests.
// create the FeatureLayer pointing to the census tracts layer
const featureLayer = new FeatureLayer({
portalItem: {
id: "6885d0bc6bdc402683eff443e7081ef6"
},
// needed for query and popup
// having fields on the client side improves performance
// for example popup can display field values without making a request to the server
outFields: [
"County", "NAME", "GEOID", "B12001_calc_pctDivorcedE",
"B12001_calc_pctMarriedE", "B12001_calc_pctNeverE",
"B12001_calc_numDivorcedE", "B12001_calc_numMarriedE", "B12001_calc_numNeverE"
],
});After adding the layer to the map, its Feature can be accessed via the view’s whenLayerView() method.
// wait for the layer view to be created
const layerView = await viewElement.whenLayerView(featureLayer);
// do something with the layerViewThe sample queries features whenever the map is panned or navigated to a new extent to update the list. However, before running the query, the sample waits until the Feature has finished fetching data for that extent by checking that its data property is false. This ensures that the query is executed against the most current set of features available in the view, avoiding incomplete or outdated results.
// watch for the layer view to finish fetching its data
// layer view will fetch data as the user navigates the map
reactiveUtils.when(
() => !layerView.dataUpdating,
async () => {
// query all the features within the view's extent.
try {
const featureSet = await layerView.queryFeatures({
geometry: viewElement.extent,
returnGeometry: true,
orderByFields: ["GEOID"],
});
// store the queried features for later use
graphics = featureSet.features;
// populate the list with the queried features
// use createDocumentFragment for better performance
const fragment = document.createDocumentFragment();
// loop through the features and create a list item for each
// displaying the census tract name
// users can click on a list item to zoom to the feature and open a popup
graphics.forEach((result, index) => {
const attributes = result.attributes;
const name = attributes.NAME;
const item = document.createElement("calcite-list-item");
item.setAttribute("label", name);
item.setAttribute("value", index);
item.addEventListener("calciteListItemSelect", onListClickHandler);
fragment.appendChild(item);
});
// Empty the current list
resultsList.innerHTML = "";
resultsList.appendChild(fragment);
} catch (error) {
console.error("query failed: ", error);
}
},
);When a list item is selected, the map zooms to the feature and opens its popup at the feature’s centroid, calculated using centroidOperator.
// zoom to the feature's extent and open a popup
await viewElement.goTo(result.geometry.extent.expand(2));
const centroid = centroidOperator.execute(result.geometry);
viewElement.openPopup({
features: [result],
location: centroid,
});