FeatureTable with a map

This sample demonstrates how to add a FeatureTable widget to your application. The FeatureTable allows users to view and sort data and attributes from a FeatureLayer. In this example, the table is displayed in addition to its associated map.

It is possible to select a feature in the table and have its associated feature automatically reflect as highlighted in the map. In order for this to work correctly, the table's view property must be set. This sample demonstrates how to select a feature in the map and have that selection reflected within the table. The selected features are added into the FeatureTable's collection of highlightIds. If highlightEnabled is true, any features associated with this collection are highlighted.

In addition, this sample also demonstrates how to filter and have the table display only the associated features that are currently displayed within the map. It does this by listening for when the view's extent updates. Whenever a view's extent changes, the FeatureTable's filterGeometry is set to this new extent and only those features that fall within this area display.

How it works

First, we add the FeatureTable with a specified FeatureLayer and field column templates to display. The view must also be set in order for any selected row(s) in the table to display its associated feature(s) as highlighted in the map.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
view.when(() => {
  //grabs the first layer in the map
  const featureLayer = webmap.layers.getItemAt(0);
  featureLayer.title = "USFS Recreational areas";

  // Create the feature table
  const featureTable = new FeatureTable({
    view: view, // Required for feature highlight to work
    layer: featureLayer,
    visibleElements: {
      // Autocast to VisibleElements
      menuItems: {
        clearSelection: true,
        refreshData: true,
        toggleColumns: true,
        selectedRecordsShowAllToggle: true,
        selectedRecordsShowSelectedToggle: true,
        zoomToSelection: true
      }
    },
    tableTemplate: {
      // Autocast to TableTemplate
      columnTemplates: [
      // Takes an array of FieldColumnTemplate and GroupColumnTemplate
      {
        // Autocast to FieldColumnTemplate
        type: "field",
        fieldName: "Name",
        label: "Recreation area name",
        direction: "asc"
      },
      {
        type: "field",
        fieldName: "Forest_name",
        label: "Forest name"
      },
      {
        type: "field",
        fieldName: "Open_status",
        label: "Open status"
      },
      {
        type: "field",
        fieldName: "Season_starts",
        label: "Season begins"
      },
      {
        type: "field",
        fieldName: "URL",
        label: "Recreation URL"
      }]
    },
    container: document.getElementById("tableDiv")
  });
...
});

Next, listen for when the view is stationary. If true, set the table to display only the attributes for the features falling within this extent.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
reactiveUtils.when(
  () => view.stationary,
  () => {
    // Filter out and show only the visible features in the feature table.
    featureTable.filterGeometry = view.extent;
  },
  {
    initial: true
  }
);

Next, listen for the view's immediate-click event. It performs a hitTest on the point location and, if applicable, selects the corresponding feature's row in the table. It does this by adding its associated ObjectId into the FeatureTable's highlightIds collection.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
view.on("immediate-click", async (event) => {
  const response = await view.hitTest(event);

  candidate = response.results.find((result) => {
    return result.graphic && result.graphic.layer && result.graphic.layer === featureLayer;
  });

  // Add the graphic's ObjectId into the collection of highlightIds.
  // Check that the featureTable.highlightIds collection
  // does not include an already highlighted feature.
  if (candidate) {
    const objectId = candidate.graphic.getObjectId();

    if (featureTable.highlightIds.includes(objectId)) {
      // Remove feature from current selection if feature
      // is already added to highlightIds collection
      featureTable.highlightIds.remove(objectId);
    } else {
      // Add this feature to the featureTable highlightIds collection
      featureTable.highlightIds.add(objectId);
    }
  }
});

Lastly, the sample also watches for any changes to highlightIds' length. If updated, it then iterates through any activeFilters. If showing a selection of features, it listens for any updates, (i.e. removing/adding), and updates the selection filter appropriately.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
reactiveUtils.watch(
  () => featureTable.highlightIds.length,
  (highlightIdsCount) => {
    // Iterate through the filters within the table.
    // If the active filter is "Show selection",
    // changes made to highlightIds (adding/removing)
    // are reflected.

    featureTable.viewModel.activeFilters.forEach((filter) => {
      if (filter.type === "selection") {
        selectionIdCount = filter.objectIds.length; // the filtered selection's id count
        // Check that the filter selection count is equal to the
        // highlightIds collection count. If not, update filter selection.
        if (selectionIdCount !== highlightIdsCount) {
          featureTable.filterBySelection();
        }
      }
    });
  }
);

Known Limitations

For a comprehensive list of limitations, please refer to the widget's API Reference documentation.

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.