Query a feature layer (SQL)

Learn how to execute a SQL query to access polygon features from a feature layer.

A feature layer can contain a large number of features stored in ArcGIS. To access a subset of the features, you can execute either a SQL or spatial query, or both at the same time. You can return feature attributes, geometry, or both attributes and geometry for each record. SQL and spatial queries are useful when you want to access only a subset of your hosted data.

In this tutorial, you perform server-side SQL queries to return a subset of features in the LA County Parcel feature layer. The feature layer contains over 2.4 million features. The resulting features are displayed as graphics on the map.

Prerequisites

You need a free ArcGIS developer account to access your dashboard and API keys. The API key must be scoped to access the services used in this tutorial.

Steps

Create a new pen

  1. To get started, either complete the Display a map tutorial or .

Set the API key

To access ArcGIS services, you need an API key.

  1. Go to your dashboard to get an API key.

  2. In CodePen, set the apiKey to your key, so it can be used to access basemap layer and location services.

    Change line
        
    esriConfig.apiKey = "YOUR-API-KEY";
    const map = new Map({
      basemap: "arcgis-topographic" //Basemap layer service
    });
    

Add modules

  1. In the require statement, add the FeatureLayer module.

    The ArcGIS API for JavaScript uses AMD modules. The require function is used to load modules so they can be used in the main function. It's important to keep the module references and function parameters in the same order.

    Add line.Change line
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>

Create a SQL selector

ArcGIS feature layers support a standard SQL query where clause. Use an HTML select element to provide a list of SQL queries for the LA County Parcel feature layer.

  1. Create a parcelType array of SQL queries. Assign the whereClause element to a SQL query from the array.

    Add line.Add line.Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  2. Create a parent select element and add option elements for each SQL query. Add some some basic styles to the elements.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  3. Add the select element to the top-right corner of the view.

    Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  4. Add an event listener to listen for select element changes.

    Add line.Add line.Add line.Add line.Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  5. Verify that the select element is created.

Create a feature layer to query

Use the FeatureLayer class to access the LA County Parcel feature layer. Since you are performing a server-side query, the feature layer does not need to be added to the map.

  1. Create a parcelLayer and set the url property to access the feature layer in the feature service.

    Add line.Add line.Add line.Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>

Execute a query

Use the queryFeatures method to perform a SQL query against the feature layer. The Query task will be autocast when the method is called.

  1. Create a queryFeatureLayer function with extent parameter. Define a parcelQuery element and set the where property to the whereClause. Set the spatialProperty to only return features that intersect the geometry, which is restricted to the visible extent of the map. The outFields property will return only a subset of the attributes. Lastly, set returnGeometry to true so that the features can be displayed.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  2. Call the queryFeatures method on the parcelLayer using parcelQuery. To view the number of features returned, write the result length to the console. This will be updated in the next step.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  3. Update the event handler to call the queryFeatureLayer function when the selector changes.

    Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  4. At the top-right, click Run. Choose a SQL query from the selector. At the bottom left, click Console to view the number of features returned from each query.

Display features

To display the features returned from the SQL query, add them to the view as polygon graphics. Define a pop-up also so the attributes can be displayed when features are clicked.

  1. Create a displayResults function with results as a parameter. Define a symbol and popupTemplate variable to style and display a pop-up for polygon graphics. The attributes referenced match the outFields specified in the query earlier.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  2. Assign the symbol and popupTemplate elements to each feature returned from the query.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  3. Clear the existing graphics and pop-up, and then add the new features returned to the view.

    Add line.Add line.Add line.Add line.Add line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>
  4. Update the queryFeatureLayer function to call the displayResults function. Remove the console.log.

    Remove lineAdd line.
                                                                                                                                        
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Tutorials: Query a feature layer (SQL)</title>
      <style>
        html, body, #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        };
        .esri-ui-corner .esri-component.esri-widget--panel {
        width: 200px !important;
    };
      </style>
      <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
      <script src="https://js.arcgis.com/4.18/"></script>
      <script>
    
        require([
          "esri/config",
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
        ], function(esriConfig,Map, MapView, FeatureLayer) {
    
          esriConfig.apiKey = "YOUR-API-KEY";
    
          const map = new Map({
            basemap: "arcgis-topographic" //Basemap layer service
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            center: [-118.80543,34.03000], //Longitude, latitude
            zoom: 13
          });
    
          // SQL query array
          const parcelLayerSQL = ["Choose a SQL where clause...", "UseType = 'Residential'",  "UseType = 'Government'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "TaxRateArea = 08637", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"];
          let whereClause = parcelLayerSQL[0];
    
          // Add SQL UI
          const select = document.createElement("select","");
          select.setAttribute("class", "esri-widget esri-select");
          select.setAttribute("style", "width: 200px; font-family: 'Avenir Next'; font-size: 1em");
          parcelLayerSQL.forEach(function(query){
            let option = document.createElement("option");
            option.innerHTML = query;
            option.value = query;
            select.appendChild(option);
          });
    
          view.ui.add(select, "top-right");
    
           // Listen for changes
          select.addEventListener('change', (event) => {
            whereClause = event.target.value;
    
            queryFeatureLayer(view.extent);
    
          });
    
          // Get query layer and set up query
     const parcelLayer = new FeatureLayer({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
          });
    
          function queryFeatureLayer(extent) {
    
            const parcelQuery = {
             where: whereClause,  // Set by select element
             spatialRelationship: "intersects", // Relationship operation to apply
             geometry: extent, // Restricted to visible extent of the map
             outFields: ["APN","UseType","TaxRateCity","Roll_LandValue"], // Attributes to return
             returnGeometry: true
            };
    
            parcelLayer.queryFeatures(parcelQuery)
    
            .then((results) => {
    
              console.log("Feature count: " + results.features.length)
    
              displayResults(results);
    
            }).catch((error) => {
              console.log(error.error);
            });
    
          }
    
          function displayResults(results) {
            // Create a blue polygon
            const symbol = {
              type: "simple-fill",
              color: [ 20, 130, 200, 0.5 ],
              outline: {
                color: "white",
                width: .5
              },
            };
    
            const popupTemplate = {
              title: "Parcel {APN}",
              content: "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}"
            };
    
            // Assign styles and popup to features
            results.features.map((feature) => {
              feature.symbol = symbol;
              feature.popupTemplate = popupTemplate;
              return feature;
            });
    
            // Clear display
            view.popup.close();
            view.graphics.removeAll();
            // Add features to graphics layer
            view.graphics.addMany(results.features);
    
          }
    
        });
      </script>
    </head>
    <body>
      <div id="viewDiv"></div>
    </body>
    </html>

Run the app

In CodePen, run your code to display the map.

When the map displays, you should be able to choose a SQL query from the selector. The resulting features will be added to the map as polygon graphics. The SQL query is applied to the visible extent of the map.

What's next?

Learn how to use additional API features and ArcGIS services in these tutorials: