<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>FeatureTable with custom content | Sample | ArcGIS Maps SDK for JavaScript</title>
<link rel="stylesheet" href="https://js.arcgis.com/5.0/esri/themes/light/main.css" />
<!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
<script type="module" src="https://js.arcgis.com/5.0/"></script>
const [EsriMap, MapView, FeatureLayer, FeatureTable] = await $arcgis.import([
"@arcgis/core/views/MapView.js",
"@arcgis/core/layers/FeatureLayer.js",
"@arcgis/core/widgets/FeatureTable.js",
const linkComponentMap = new Map();
const meterComponentMap = new Map();
const expressionComponentMap = new Map();
const expressionLoadingMap = new Map();
const expressionResultMap = new Map();
const map = new EsriMap({
const view = new MapView({
center: [-118.4, 34.07], // longitude, latitude
const featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/CollegesUniversities/FeatureServer/0",
title: "US Colleges and Universities",
const components = new Set();
const table = new FeatureTable({
container: document.getElementById("table"),
view.goTo(params.feature);
fieldName: "enrollment_capacity",
label: "Enrollment Capacity",
formatFunction: ({ feature, index }) => {
const total = feature.attributes["TOT_ENROLL"];
const fullTime = feature.attributes["FT_ENROLL"];
let component = meterComponentMap.get(index);
component = document.createElement("calcite-meter");
component.value = fullTime;
meterComponentMap.set(index, component);
label: "Calculate Expression",
fieldName: "linkTestColumn", // needs to be unique
formatFunction: ({ feature, index }) => {
const objectId = feature.getObjectId() ?? feature.attributes[layer.objectIdField];
const total = feature.attributes["TOT_ENROLL"];
const fullTime = feature.attributes["FT_ENROLL"];
let component = expressionComponentMap.get(index);
let loading = expressionLoadingMap.get(objectId);
let result = expressionResultMap.get(objectId);
component.icon = "check";
component.loading = false;
component.loading = true;
component.text = "Calculating...";
component.loading = false;
component = document.createElement("calcite-action");
component.text = "Calculate";
component.textEnabled = true;
component.icon = "calculator";
component.loading = false;
component.onclick = () => {
expressionResultMap.delete(objectId);
expressionLoadingMap.set(objectId, "loading");
expressionLoadingMap.delete(objectId);
expressionResultMap.set(objectId, Math.random() * 10);
table.refreshCellContent();
(Math.random() * 4000) / 4,
table.refreshCellContent();
expressionComponentMap.set(index, component);
formatFunction: ({ feature, index }) => {
const website = feature.attributes["WEBSITE"];
let component = linkComponentMap.get(index);
component = document.createElement("calcite-link");
component.textEnabled = true;
component.iconEnd = "launch";
component.title = website;
component.href = website;
component.textContent = "School Website";
component.target = "_blank";
linkComponentMap.set(index, component);
label: "Total Employees",
label: "Ratio of Students to Employees",
fieldName: "ratioCustomColumn", // needs to be unique among columns
formatFunction: ({ feature }) => {
const enrollment = feature?.attributes["FT_ENROLL"];
const employment = feature?.attributes["TOT_EMPLOY"];
// Avoid division by zero
if (enrollment && employment && employment > 1) {
return `${Math.round((enrollment / employment) * 100) / 100} to 1`;
table.watch("state", function (newValue, oldValue) {
console.log("state change: ", newValue);
table.on("selection-change", function (evt) {
console.log("selection-change", evt);
function goTo(long, lat) {
<div class="container" id="container">