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 a SQL or spatial query, or both at the same time. You can also return the attributes, geometry, or both attributes and geometry for each record. SQL and spatial queries are useful when a feature layer is very large and you just want to access a subset of the data.

In this tutorial, you perform server-side SQL queries to return a subset of the features from the LA County Parcel hosted feature layer. The feature layer contains over 2.4 million features. The resulting features are displayed as graphics on the map. A pop-up is also used to display feature attributes.

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 location services, you need an API key.

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

  2. In CodePen, update apiKey to use your key.

    Change line
              
    //
    
    const apiKey = "YOUR-API-KEY";
    const basemapEnum = "ArcGIS:Streets";
    const map = new mapboxgl.Map({
      container: "map", // the id of the div element
      style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
      zoom: 12, // starting zoom
      center: [-118.805, 34.027] // starting location [longitude, latitude]
    });
    

Add API references

This tutorial uses ArcGIS REST JS to query the feature layer.

Add line.Add line.
                                                                                                                                                           
<!DOCTYPE html>
<html>

  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

    <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
    <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />

    <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
    <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>

    <style>
      html,
      body,
      #map {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
        font-family: Arial, Helvetica, sans-serif;
        font-size: 14px;
        color: #323232;
      }
    </style>
  </head>

  <body>
    <div id="map"></div>
    <script>

      const apiKey = "YOUR-API-KEY";

      const basemapEnum = "ArcGIS:Streets";

      const map = new mapboxgl.Map({
        container: "map", // the id of the div element
        style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
        zoom: 12, // starting zoom

        center: [-118.80543, 34.03] // starting location [longitude, latitude]

      });

      class QueryControl {
        onAdd(map) {
          const template = document.createElement("template");
          template.innerHTML = `<div class="mapboxgl-ctrl mapboxgl-ctrl-group" style="margin:20px;">
            <select style="font-size:16px; padding:4px 8px;">
              <option value="">Choose a WHERE clause...</option>
              <option>UseType = 'Residential'</option>
              <option>UseType = 'Government'</option>
              <option>UseType = 'Irrigated Farm'</option>
              <option>TaxRateArea = 10853</option>
              <option>TaxRateArea = 10860</option>
              <option>TaxRateArea = 08637</option>
              <option>Roll_LandValue > 1000000</option>
              <option>Roll_LandValue < 1000000</option>
            </select>
          </div>`;

          const select = template.content.querySelector("select");
          select.addEventListener("change", () => {
            // Do nothing for the "Choose a WHERE clause..." option
            if (select.value !== "") {
              // Get bounds in [minx, miny, maxx, maxy] format
              const bounds = map.getBounds().toArray().flat();
              executeQuery(select.value, bounds);
            }
          });

          return template.content;
        }
      }

      const queryControl = new QueryControl();
      map.addControl(queryControl);

      function addParcelLayer() {
        map.addSource("parcels", {
          type: "geojson",
          data: {
            type: "FeatureCollection",
            features: []
          }
        });

        const firstSymbolLayer = map.getStyle().layers.find((l) => l.type === "symbol");
        map.addLayer(
          {
            id: "parcels-fill",
            source: "parcels",
            type: "fill",
            paint: {
              "fill-color": "hsla(200, 80%,50%, 0.5)",

              "fill-outline-color": "hsl(360, 100%, 100%)"
            }
          },
          firstSymbolLayer.id
        ); // insert new layer before this one
        map.addLayer({
          id: "parcels-line",
          source: "parcels",
          type: "line",
          paint: {
            "line-width": 0.5,
            "line-color": "hsl(360, 100%,100%)"
          }
        }); // set outline style for parcels
      }

      map.on("load", () => {

        addParcelLayer();

      });

      function executeQuery(whereClause, geometry) {

        arcgisRest
          .queryFeatures({
            url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
            geometry: geometry,
            geometryType: "esriGeometryEnvelope",
            inSR: 4326, // EPSG:4326 uses latitudes and longitudes
            spatialRel: "esriSpatialRelIntersects",
            where: whereClause,
            f: "geojson",
            returnGeometry: true,
            outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
          })

          .then((response) => {
            map.getSource("parcels").setData(response);
          });

      }

      map.on("click", "parcels-fill", (e) => {
        const parcel = e.features[0].properties;
        const landValue = parcel.Roll_LandValue != 'null' ? `$${parcel.Roll_LandValue.toLocaleString()}` : `N/A`;
        const message =
          `<b>Parcel ${parcel.APN}</b></br>` +
          `Type: ${parcel.UseType} <br>` +
          `Land value: ${landValue} <br>` +
          `Tax Rate City: ${parcel.TaxRateCity}`;

        new mapboxgl.Popup().setHTML(message).setLngLat(e.lngLat).addTo(map);
      });

    </script>
  </body>
</html>

Create a SQL selector

Hosted 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.

To add the <select> HTML element as a Map control, you create an object that implements the Mapbox GL JS IControl interface.

Creating an IControl allows Mapbox GL JS to position it, which prevents your control overlapping other Mapbox GL JS controls.

  1. Create a QueryControl class with an onAdd function. Inside, create a <div> element with a <select> inside, with options for each of the SQL where clauses. Return this element.

    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.Add line.Add line.Add line.
                                                                                                                                                               
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          class QueryControl {
            onAdd(map) {
              const template = document.createElement("template");
              template.innerHTML = `<div class="mapboxgl-ctrl mapboxgl-ctrl-group" style="margin:20px;">
                <select style="font-size:16px; padding:4px 8px;">
                  <option value="">Choose a WHERE clause...</option>
                  <option>UseType = 'Residential'</option>
                  <option>UseType = 'Government'</option>
                  <option>UseType = 'Irrigated Farm'</option>
                  <option>TaxRateArea = 10853</option>
                  <option>TaxRateArea = 10860</option>
                  <option>TaxRateArea = 08637</option>
                  <option>Roll_LandValue > 1000000</option>
                  <option>Roll_LandValue < 1000000</option>
                </select>
              </div>`;
    
              const select = template.content.querySelector("select");
              select.addEventListener("change", () => {
                // Do nothing for the "Choose a WHERE clause..." option
                if (select.value !== "") {
                  // Get bounds in [minx, miny, maxx, maxy] format
                  const bounds = map.getBounds().toArray().flat();
                  executeQuery(select.value, bounds);
                }
              });
    
              return template.content;
            }
          }
    
          const queryControl = new QueryControl();
          map.addControl(queryControl);
    
          function addParcelLayer() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
    
            const firstSymbolLayer = map.getStyle().layers.find((l) => l.type === "symbol");
            map.addLayer(
              {
                id: "parcels-fill",
                source: "parcels",
                type: "fill",
                paint: {
                  "fill-color": "hsla(200, 80%,50%, 0.5)",
    
                  "fill-outline-color": "hsl(360, 100%, 100%)"
                }
              },
              firstSymbolLayer.id
            ); // insert new layer before this one
            map.addLayer({
              id: "parcels-line",
              source: "parcels",
              type: "line",
              paint: {
                "line-width": 0.5,
                "line-color": "hsl(360, 100%,100%)"
              }
            }); // set outline style for parcels
          }
    
          map.on("load", () => {
    
            addParcelLayer();
    
          });
    
          function executeQuery(whereClause, geometry) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: "esriGeometryEnvelope",
                inSR: 4326, // EPSG:4326 uses latitudes and longitudes
                spatialRel: "esriSpatialRelIntersects",
                where: whereClause,
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const parcel = e.features[0].properties;
            const landValue = parcel.Roll_LandValue != 'null' ? `$${parcel.Roll_LandValue.toLocaleString()}` : `N/A`;
            const message =
              `<b>Parcel ${parcel.APN}</b></br>` +
              `Type: ${parcel.UseType} <br>` +
              `Land value: ${landValue} <br>` +
              `Tax Rate City: ${parcel.TaxRateCity}`;
    
            new mapboxgl.Popup().setHTML(message).setLngLat(e.lngLat).addTo(map);
          });
    
        </script>
      </body>
    </html>
  2. Create a QueryControl and add it to the Map with map.addControl.

    Add line.Add line.
                                                                                                                                                               
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          class QueryControl {
            onAdd(map) {
              const template = document.createElement("template");
              template.innerHTML = `<div class="mapboxgl-ctrl mapboxgl-ctrl-group" style="margin:20px;">
                <select style="font-size:16px; padding:4px 8px;">
                  <option value="">Choose a WHERE clause...</option>
                  <option>UseType = 'Residential'</option>
                  <option>UseType = 'Government'</option>
                  <option>UseType = 'Irrigated Farm'</option>
                  <option>TaxRateArea = 10853</option>
                  <option>TaxRateArea = 10860</option>
                  <option>TaxRateArea = 08637</option>
                  <option>Roll_LandValue > 1000000</option>
                  <option>Roll_LandValue < 1000000</option>
                </select>
              </div>`;
    
              const select = template.content.querySelector("select");
              select.addEventListener("change", () => {
                // Do nothing for the "Choose a WHERE clause..." option
                if (select.value !== "") {
                  // Get bounds in [minx, miny, maxx, maxy] format
                  const bounds = map.getBounds().toArray().flat();
                  executeQuery(select.value, bounds);
                }
              });
    
              return template.content;
            }
          }
    
          const queryControl = new QueryControl();
          map.addControl(queryControl);
    
          function addParcelLayer() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
    
            const firstSymbolLayer = map.getStyle().layers.find((l) => l.type === "symbol");
            map.addLayer(
              {
                id: "parcels-fill",
                source: "parcels",
                type: "fill",
                paint: {
                  "fill-color": "hsla(200, 80%,50%, 0.5)",
    
                  "fill-outline-color": "hsl(360, 100%, 100%)"
                }
              },
              firstSymbolLayer.id
            ); // insert new layer before this one
            map.addLayer({
              id: "parcels-line",
              source: "parcels",
              type: "line",
              paint: {
                "line-width": 0.5,
                "line-color": "hsl(360, 100%,100%)"
              }
            }); // set outline style for parcels
          }
    
          map.on("load", () => {
    
            addParcelLayer();
    
          });
    
          function executeQuery(whereClause, geometry) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: "esriGeometryEnvelope",
                inSR: 4326, // EPSG:4326 uses latitudes and longitudes
                spatialRel: "esriSpatialRelIntersects",
                where: whereClause,
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const parcel = e.features[0].properties;
            const landValue = parcel.Roll_LandValue != 'null' ? `$${parcel.Roll_LandValue.toLocaleString()}` : `N/A`;
            const message =
              `<b>Parcel ${parcel.APN}</b></br>` +
              `Type: ${parcel.UseType} <br>` +
              `Land value: ${landValue} <br>` +
              `Tax Rate City: ${parcel.TaxRateCity}`;
    
            new mapboxgl.Popup().setHTML(message).setLngLat(e.lngLat).addTo(map);
          });
    
        </script>
      </body>
    </html>

Add parcel layer

Parcels returned by the query are simple GeoJSON polygons. You can display them with a GeoJSON source and a fill layer.

  1. Create an addParcelLayer function. Inside, add a GeoJSON source and a fill layer. Add the layer before the first symbol layer.

    By inserting the polygon layer beneath the icon and text layers, it keeps the labels readable. In Mapbox GL JS, there is no distinction between "basemap" layers and "overlay layers", so you can insert the layer anywhere.

    To determine the first symbol layer, you can use map.getStyle to get the style, then iterate to find the first layer whose type is symbol.

    See the Mapbox GL JS documentation for details.

    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.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.
                                                                                                                                                               
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          class QueryControl {
            onAdd(map) {
              const template = document.createElement("template");
              template.innerHTML = `<div class="mapboxgl-ctrl mapboxgl-ctrl-group" style="margin:20px;">
                <select style="font-size:16px; padding:4px 8px;">
                  <option value="">Choose a WHERE clause...</option>
                  <option>UseType = 'Residential'</option>
                  <option>UseType = 'Government'</option>
                  <option>UseType = 'Irrigated Farm'</option>
                  <option>TaxRateArea = 10853</option>
                  <option>TaxRateArea = 10860</option>
                  <option>TaxRateArea = 08637</option>
                  <option>Roll_LandValue > 1000000</option>
                  <option>Roll_LandValue < 1000000</option>
                </select>
              </div>`;
    
              const select = template.content.querySelector("select");
              select.addEventListener("change", () => {
                // Do nothing for the "Choose a WHERE clause..." option
                if (select.value !== "") {
                  // Get bounds in [minx, miny, maxx, maxy] format
                  const bounds = map.getBounds().toArray().flat();
                  executeQuery(select.value, bounds);
                }
              });
    
              return template.content;
            }
          }
    
          const queryControl = new QueryControl();
          map.addControl(queryControl);
    
          function addParcelLayer() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
    
            const firstSymbolLayer = map.getStyle().layers.find((l) => l.type === "symbol");
            map.addLayer(
              {
                id: "parcels-fill",
                source: "parcels",
                type: "fill",
                paint: {
                  "fill-color": "hsla(200, 80%,50%, 0.5)",
    
                  "fill-outline-color": "hsl(360, 100%, 100%)"
                }
              },
              firstSymbolLayer.id
            ); // insert new layer before this one
            map.addLayer({
              id: "parcels-line",
              source: "parcels",
              type: "line",
              paint: {
                "line-width": 0.5,
                "line-color": "hsl(360, 100%,100%)"
              }
            }); // set outline style for parcels
          }
    
          map.on("load", () => {
    
            addParcelLayer();
    
          });
    
          function executeQuery(whereClause, geometry) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: "esriGeometryEnvelope",
                inSR: 4326, // EPSG:4326 uses latitudes and longitudes
                spatialRel: "esriSpatialRelIntersects",
                where: whereClause,
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const parcel = e.features[0].properties;
            const landValue = parcel.Roll_LandValue != 'null' ? `$${parcel.Roll_LandValue.toLocaleString()}` : `N/A`;
            const message =
              `<b>Parcel ${parcel.APN}</b></br>` +
              `Type: ${parcel.UseType} <br>` +
              `Land value: ${landValue} <br>` +
              `Tax Rate City: ${parcel.TaxRateCity}`;
    
            new mapboxgl.Popup().setHTML(message).setLngLat(e.lngLat).addTo(map);
          });
    
        </script>
      </body>
    </html>

Add load handler

To add layers to the map, you need to use the load event to ensure the map is fully loaded.

  1. Add an event handler for the load event. Inside, call addParcelLayer.

    Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                               
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          class QueryControl {
            onAdd(map) {
              const template = document.createElement("template");
              template.innerHTML = `<div class="mapboxgl-ctrl mapboxgl-ctrl-group" style="margin:20px;">
                <select style="font-size:16px; padding:4px 8px;">
                  <option value="">Choose a WHERE clause...</option>
                  <option>UseType = 'Residential'</option>
                  <option>UseType = 'Government'</option>
                  <option>UseType = 'Irrigated Farm'</option>
                  <option>TaxRateArea = 10853</option>
                  <option>TaxRateArea = 10860</option>
                  <option>TaxRateArea = 08637</option>
                  <option>Roll_LandValue > 1000000</option>
                  <option>Roll_LandValue < 1000000</option>
                </select>
              </div>`;
    
              const select = template.content.querySelector("select");
              select.addEventListener("change", () => {
                // Do nothing for the "Choose a WHERE clause..." option
                if (select.value !== "") {
                  // Get bounds in [minx, miny, maxx, maxy] format
                  const bounds = map.getBounds().toArray().flat();
                  executeQuery(select.value, bounds);
                }
              });
    
              return template.content;
            }
          }
    
          const queryControl = new QueryControl();
          map.addControl(queryControl);
    
          function addParcelLayer() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
    
            const firstSymbolLayer = map.getStyle().layers.find((l) => l.type === "symbol");
            map.addLayer(
              {
                id: "parcels-fill",
                source: "parcels",
                type: "fill",
                paint: {
                  "fill-color": "hsla(200, 80%,50%, 0.5)",
    
                  "fill-outline-color": "hsl(360, 100%, 100%)"
                }
              },
              firstSymbolLayer.id
            ); // insert new layer before this one
            map.addLayer({
              id: "parcels-line",
              source: "parcels",
              type: "line",
              paint: {
                "line-width": 0.5,
                "line-color": "hsl(360, 100%,100%)"
              }
            }); // set outline style for parcels
          }
    
          map.on("load", () => {
    
            addParcelLayer();
    
          });
    
          function executeQuery(whereClause, geometry) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: "esriGeometryEnvelope",
                inSR: 4326, // EPSG:4326 uses latitudes and longitudes
                spatialRel: "esriSpatialRelIntersects",
                where: whereClause,
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const parcel = e.features[0].properties;
            const landValue = parcel.Roll_LandValue != 'null' ? `$${parcel.Roll_LandValue.toLocaleString()}` : `N/A`;
            const message =
              `<b>Parcel ${parcel.APN}</b></br>` +
              `Type: ${parcel.UseType} <br>` +
              `Land value: ${landValue} <br>` +
              `Tax Rate City: ${parcel.TaxRateCity}`;
    
            new mapboxgl.Popup().setHTML(message).setLngLat(e.lngLat).addTo(map);
          });
    
        </script>
      </body>
    </html>

Execute the query

Use the ArcGIS REST JS queryFeatures method to find features in the LA County Parcels feature layer that match the selected where clause.

To limit the query results to the visible extent of the Map, you can set the queryFeatures geometry property. To do so, use map.getBounds to get the extent of the Map viewport, and then convert it to the required esriGeometryEnvelope format of [minx, miny, maxx, maxy]. This confines the SQL query to the geographic bounds (extent) of the map.

When the matching parcels are returned, call setData on the parcels source to display them.

  1. Create a function called executeQuery with whereClause and geometry parameters. Inside, create a new arcgisRest.ApiKey to access the feature service. Call arcgisRest.queryFeatures. Pass the geometry and geometryType. Specify GeoJSON as the return type, requesting returnGeometry and specific outFields. All of the features within the geometry will be returned with attribute information set by the outFields property.

    There are many other spatial relationships that you can specify with spatialRel. For example, you can use esriSpatialRelContains to only return parcels completely within the viewport. See the ArcGIS REST API documentation for details.

    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.
                                                                                                                                                               
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          class QueryControl {
            onAdd(map) {
              const template = document.createElement("template");
              template.innerHTML = `<div class="mapboxgl-ctrl mapboxgl-ctrl-group" style="margin:20px;">
                <select style="font-size:16px; padding:4px 8px;">
                  <option value="">Choose a WHERE clause...</option>
                  <option>UseType = 'Residential'</option>
                  <option>UseType = 'Government'</option>
                  <option>UseType = 'Irrigated Farm'</option>
                  <option>TaxRateArea = 10853</option>
                  <option>TaxRateArea = 10860</option>
                  <option>TaxRateArea = 08637</option>
                  <option>Roll_LandValue > 1000000</option>
                  <option>Roll_LandValue < 1000000</option>
                </select>
              </div>`;
    
              const select = template.content.querySelector("select");
              select.addEventListener("change", () => {
                // Do nothing for the "Choose a WHERE clause..." option
                if (select.value !== "") {
                  // Get bounds in [minx, miny, maxx, maxy] format
                  const bounds = map.getBounds().toArray().flat();
                  executeQuery(select.value, bounds);
                }
              });
    
              return template.content;
            }
          }
    
          const queryControl = new QueryControl();
          map.addControl(queryControl);
    
          function addParcelLayer() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
    
            const firstSymbolLayer = map.getStyle().layers.find((l) => l.type === "symbol");
            map.addLayer(
              {
                id: "parcels-fill",
                source: "parcels",
                type: "fill",
                paint: {
                  "fill-color": "hsla(200, 80%,50%, 0.5)",
    
                  "fill-outline-color": "hsl(360, 100%, 100%)"
                }
              },
              firstSymbolLayer.id
            ); // insert new layer before this one
            map.addLayer({
              id: "parcels-line",
              source: "parcels",
              type: "line",
              paint: {
                "line-width": 0.5,
                "line-color": "hsl(360, 100%,100%)"
              }
            }); // set outline style for parcels
          }
    
          map.on("load", () => {
    
            addParcelLayer();
    
          });
    
          function executeQuery(whereClause, geometry) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: "esriGeometryEnvelope",
                inSR: 4326, // EPSG:4326 uses latitudes and longitudes
                spatialRel: "esriSpatialRelIntersects",
                where: whereClause,
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const parcel = e.features[0].properties;
            const landValue = parcel.Roll_LandValue != 'null' ? `$${parcel.Roll_LandValue.toLocaleString()}` : `N/A`;
            const message =
              `<b>Parcel ${parcel.APN}</b></br>` +
              `Type: ${parcel.UseType} <br>` +
              `Land value: ${landValue} <br>` +
              `Tax Rate City: ${parcel.TaxRateCity}`;
    
            new mapboxgl.Popup().setHTML(message).setLngLat(e.lngLat).addTo(map);
          });
    
        </script>
      </body>
    </html>
  2. Add a response handler. Inside, set the returned parcels as the data for the parcels source.

    Add line.Add line.Add line.
                                                                                                                                                               
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          class QueryControl {
            onAdd(map) {
              const template = document.createElement("template");
              template.innerHTML = `<div class="mapboxgl-ctrl mapboxgl-ctrl-group" style="margin:20px;">
                <select style="font-size:16px; padding:4px 8px;">
                  <option value="">Choose a WHERE clause...</option>
                  <option>UseType = 'Residential'</option>
                  <option>UseType = 'Government'</option>
                  <option>UseType = 'Irrigated Farm'</option>
                  <option>TaxRateArea = 10853</option>
                  <option>TaxRateArea = 10860</option>
                  <option>TaxRateArea = 08637</option>
                  <option>Roll_LandValue > 1000000</option>
                  <option>Roll_LandValue < 1000000</option>
                </select>
              </div>`;
    
              const select = template.content.querySelector("select");
              select.addEventListener("change", () => {
                // Do nothing for the "Choose a WHERE clause..." option
                if (select.value !== "") {
                  // Get bounds in [minx, miny, maxx, maxy] format
                  const bounds = map.getBounds().toArray().flat();
                  executeQuery(select.value, bounds);
                }
              });
    
              return template.content;
            }
          }
    
          const queryControl = new QueryControl();
          map.addControl(queryControl);
    
          function addParcelLayer() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
    
            const firstSymbolLayer = map.getStyle().layers.find((l) => l.type === "symbol");
            map.addLayer(
              {
                id: "parcels-fill",
                source: "parcels",
                type: "fill",
                paint: {
                  "fill-color": "hsla(200, 80%,50%, 0.5)",
    
                  "fill-outline-color": "hsl(360, 100%, 100%)"
                }
              },
              firstSymbolLayer.id
            ); // insert new layer before this one
            map.addLayer({
              id: "parcels-line",
              source: "parcels",
              type: "line",
              paint: {
                "line-width": 0.5,
                "line-color": "hsl(360, 100%,100%)"
              }
            }); // set outline style for parcels
          }
    
          map.on("load", () => {
    
            addParcelLayer();
    
          });
    
          function executeQuery(whereClause, geometry) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: "esriGeometryEnvelope",
                inSR: 4326, // EPSG:4326 uses latitudes and longitudes
                spatialRel: "esriSpatialRelIntersects",
                where: whereClause,
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const parcel = e.features[0].properties;
            const landValue = parcel.Roll_LandValue != 'null' ? `$${parcel.Roll_LandValue.toLocaleString()}` : `N/A`;
            const message =
              `<b>Parcel ${parcel.APN}</b></br>` +
              `Type: ${parcel.UseType} <br>` +
              `Land value: ${landValue} <br>` +
              `Tax Rate City: ${parcel.TaxRateCity}`;
    
            new mapboxgl.Popup().setHTML(message).setLngLat(e.lngLat).addTo(map);
          });
    
        </script>
      </body>
    </html>
  3. Update your QueryControl to add a change event handler to the select element. Inside, calculate the viewport extent and call executeQuery with the extent and where clause.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                               
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          class QueryControl {
            onAdd(map) {
              const template = document.createElement("template");
              template.innerHTML = `<div class="mapboxgl-ctrl mapboxgl-ctrl-group" style="margin:20px;">
                <select style="font-size:16px; padding:4px 8px;">
                  <option value="">Choose a WHERE clause...</option>
                  <option>UseType = 'Residential'</option>
                  <option>UseType = 'Government'</option>
                  <option>UseType = 'Irrigated Farm'</option>
                  <option>TaxRateArea = 10853</option>
                  <option>TaxRateArea = 10860</option>
                  <option>TaxRateArea = 08637</option>
                  <option>Roll_LandValue > 1000000</option>
                  <option>Roll_LandValue < 1000000</option>
                </select>
              </div>`;
    
              const select = template.content.querySelector("select");
              select.addEventListener("change", () => {
                // Do nothing for the "Choose a WHERE clause..." option
                if (select.value !== "") {
                  // Get bounds in [minx, miny, maxx, maxy] format
                  const bounds = map.getBounds().toArray().flat();
                  executeQuery(select.value, bounds);
                }
              });
    
              return template.content;
            }
          }
    
          const queryControl = new QueryControl();
          map.addControl(queryControl);
    
          function addParcelLayer() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
    
            const firstSymbolLayer = map.getStyle().layers.find((l) => l.type === "symbol");
            map.addLayer(
              {
                id: "parcels-fill",
                source: "parcels",
                type: "fill",
                paint: {
                  "fill-color": "hsla(200, 80%,50%, 0.5)",
    
                  "fill-outline-color": "hsl(360, 100%, 100%)"
                }
              },
              firstSymbolLayer.id
            ); // insert new layer before this one
            map.addLayer({
              id: "parcels-line",
              source: "parcels",
              type: "line",
              paint: {
                "line-width": 0.5,
                "line-color": "hsl(360, 100%,100%)"
              }
            }); // set outline style for parcels
          }
    
          map.on("load", () => {
    
            addParcelLayer();
    
          });
    
          function executeQuery(whereClause, geometry) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: "esriGeometryEnvelope",
                inSR: 4326, // EPSG:4326 uses latitudes and longitudes
                spatialRel: "esriSpatialRelIntersects",
                where: whereClause,
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const parcel = e.features[0].properties;
            const landValue = parcel.Roll_LandValue != 'null' ? `$${parcel.Roll_LandValue.toLocaleString()}` : `N/A`;
            const message =
              `<b>Parcel ${parcel.APN}</b></br>` +
              `Type: ${parcel.UseType} <br>` +
              `Land value: ${landValue} <br>` +
              `Tax Rate City: ${parcel.TaxRateCity}`;
    
            new mapboxgl.Popup().setHTML(message).setLngLat(e.lngLat).addTo(map);
          });
    
        </script>
      </body>
    </html>
  4. At the top right, click Run. When you select a where clause using the toolbox, a query will run against the feature layer and display all land parcels within the current viewport matching the where clause.

Add a pop-up

You can add a Popup to view attributes of a parcel when the user clicks on it.

See the Display a pop-up tutorial for more details.

  1. Add a click event handler to the parcels-fill layer. Inside, construct the pop-up content from the attributes of the clicked parcel. Create a new Popup, then use popup.setHTML to set the content. Set the position of the pop-up and add it to the map.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                               
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          class QueryControl {
            onAdd(map) {
              const template = document.createElement("template");
              template.innerHTML = `<div class="mapboxgl-ctrl mapboxgl-ctrl-group" style="margin:20px;">
                <select style="font-size:16px; padding:4px 8px;">
                  <option value="">Choose a WHERE clause...</option>
                  <option>UseType = 'Residential'</option>
                  <option>UseType = 'Government'</option>
                  <option>UseType = 'Irrigated Farm'</option>
                  <option>TaxRateArea = 10853</option>
                  <option>TaxRateArea = 10860</option>
                  <option>TaxRateArea = 08637</option>
                  <option>Roll_LandValue > 1000000</option>
                  <option>Roll_LandValue < 1000000</option>
                </select>
              </div>`;
    
              const select = template.content.querySelector("select");
              select.addEventListener("change", () => {
                // Do nothing for the "Choose a WHERE clause..." option
                if (select.value !== "") {
                  // Get bounds in [minx, miny, maxx, maxy] format
                  const bounds = map.getBounds().toArray().flat();
                  executeQuery(select.value, bounds);
                }
              });
    
              return template.content;
            }
          }
    
          const queryControl = new QueryControl();
          map.addControl(queryControl);
    
          function addParcelLayer() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
    
            const firstSymbolLayer = map.getStyle().layers.find((l) => l.type === "symbol");
            map.addLayer(
              {
                id: "parcels-fill",
                source: "parcels",
                type: "fill",
                paint: {
                  "fill-color": "hsla(200, 80%,50%, 0.5)",
    
                  "fill-outline-color": "hsl(360, 100%, 100%)"
                }
              },
              firstSymbolLayer.id
            ); // insert new layer before this one
            map.addLayer({
              id: "parcels-line",
              source: "parcels",
              type: "line",
              paint: {
                "line-width": 0.5,
                "line-color": "hsl(360, 100%,100%)"
              }
            }); // set outline style for parcels
          }
    
          map.on("load", () => {
    
            addParcelLayer();
    
          });
    
          function executeQuery(whereClause, geometry) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: "esriGeometryEnvelope",
                inSR: 4326, // EPSG:4326 uses latitudes and longitudes
                spatialRel: "esriSpatialRelIntersects",
                where: whereClause,
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const parcel = e.features[0].properties;
            const landValue = parcel.Roll_LandValue != 'null' ? `$${parcel.Roll_LandValue.toLocaleString()}` : `N/A`;
            const message =
              `<b>Parcel ${parcel.APN}</b></br>` +
              `Type: ${parcel.UseType} <br>` +
              `Land value: ${landValue} <br>` +
              `Tax Rate City: ${parcel.TaxRateCity}`;
    
            new mapboxgl.Popup().setHTML(message).setLngLat(e.lngLat).addTo(map);
          });
    
        </script>
      </body>
    </html>

Run the app

In CodePen, run your code to display the map.

When the map displays, you should be able to use the query selector to display parcels. Click on a parcel to show a pop-up with the feature's attributes.

What's next?

Learn how to use additional ArcGIS location services in these tutorials: