@saschabrunnerch/arcgis-maps-sdk-js-ai-context 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +163 -203
  2. package/bin/cli.js +157 -173
  3. package/contexts/4.34/{claude → skills}/arcgis-3d-advanced/SKILL.md +586 -586
  4. package/contexts/4.34/{claude → skills}/arcgis-advanced-layers/SKILL.md +431 -431
  5. package/contexts/4.34/{claude → skills}/arcgis-analysis-services/SKILL.md +607 -607
  6. package/contexts/4.34/{claude → skills}/arcgis-authentication/SKILL.md +301 -301
  7. package/contexts/4.34/{claude → skills}/arcgis-cim-symbols/SKILL.md +486 -486
  8. package/contexts/4.34/{claude → skills}/arcgis-coordinates-projection/SKILL.md +406 -406
  9. package/contexts/4.34/{claude → skills}/arcgis-core-maps/SKILL.md +739 -739
  10. package/contexts/4.34/{claude → skills}/arcgis-core-utilities/SKILL.md +732 -732
  11. package/contexts/4.34/{claude → skills}/arcgis-custom-rendering/SKILL.md +445 -445
  12. package/contexts/4.34/{claude → skills}/arcgis-editing-advanced/SKILL.md +702 -702
  13. package/contexts/4.34/{claude → skills}/arcgis-feature-effects/SKILL.md +393 -393
  14. package/contexts/4.34/{claude → skills}/arcgis-geometry-operations/SKILL.md +489 -489
  15. package/contexts/4.34/{claude → skills}/arcgis-imagery/SKILL.md +307 -307
  16. package/contexts/4.34/{claude → skills}/arcgis-interaction/SKILL.md +572 -572
  17. package/contexts/4.34/{claude → skills}/arcgis-knowledge-graphs/SKILL.md +582 -582
  18. package/contexts/4.34/{claude → skills}/arcgis-layers/SKILL.md +601 -601
  19. package/contexts/4.34/{claude → skills}/arcgis-map-tools/SKILL.md +668 -668
  20. package/contexts/4.34/{claude → skills}/arcgis-media-layers/SKILL.md +290 -290
  21. package/contexts/4.34/{claude → skills}/arcgis-portal-content/SKILL.md +679 -679
  22. package/contexts/4.34/{claude → skills}/arcgis-scene-effects/SKILL.md +512 -512
  23. package/contexts/4.34/{claude → skills}/arcgis-smart-mapping/SKILL.md +686 -686
  24. package/contexts/4.34/{claude → skills}/arcgis-starter-app-extended/SKILL.md +649 -649
  25. package/contexts/4.34/{claude → skills}/arcgis-tables-forms/SKILL.md +877 -877
  26. package/contexts/4.34/{claude → skills}/arcgis-time-animation/SKILL.md +722 -722
  27. package/contexts/4.34/{claude → skills}/arcgis-utility-networks/SKILL.md +301 -301
  28. package/contexts/4.34/{claude → skills}/arcgis-visualization/SKILL.md +580 -580
  29. package/contexts/4.34/{claude → skills}/arcgis-widgets-ui/SKILL.md +574 -574
  30. package/lib/installer.js +19 -104
  31. package/package.json +45 -45
  32. package/contexts/4.34/copilot/arcgis-3d.instructions.md +0 -267
  33. package/contexts/4.34/copilot/arcgis-analysis.instructions.md +0 -294
  34. package/contexts/4.34/copilot/arcgis-arcade.instructions.md +0 -234
  35. package/contexts/4.34/copilot/arcgis-authentication.instructions.md +0 -187
  36. package/contexts/4.34/copilot/arcgis-cim-symbols.instructions.md +0 -177
  37. package/contexts/4.34/copilot/arcgis-core-maps.instructions.md +0 -246
  38. package/contexts/4.34/copilot/arcgis-core-utilities.instructions.md +0 -247
  39. package/contexts/4.34/copilot/arcgis-editing.instructions.md +0 -262
  40. package/contexts/4.34/copilot/arcgis-geometry.instructions.md +0 -225
  41. package/contexts/4.34/copilot/arcgis-layers.instructions.md +0 -278
  42. package/contexts/4.34/copilot/arcgis-popup-templates.instructions.md +0 -266
  43. package/contexts/4.34/copilot/arcgis-portal-advanced.instructions.md +0 -275
  44. package/contexts/4.34/copilot/arcgis-smart-mapping.instructions.md +0 -184
  45. package/contexts/4.34/copilot/arcgis-starter-app-extended.instructions.md +0 -643
  46. package/contexts/4.34/copilot/arcgis-starter-app.instructions.md +0 -268
  47. package/contexts/4.34/copilot/arcgis-time-animation.instructions.md +0 -112
  48. package/contexts/4.34/copilot/arcgis-visualization.instructions.md +0 -321
  49. package/contexts/4.34/copilot/arcgis-widgets-ui.instructions.md +0 -277
  50. /package/contexts/4.34/{claude → skills}/arcgis-arcade/SKILL.md +0 -0
  51. /package/contexts/4.34/{claude → skills}/arcgis-popup-templates/SKILL.md +0 -0
  52. /package/contexts/4.34/{claude → skills}/arcgis-starter-app/SKILL.md +0 -0
@@ -1,877 +1,877 @@
1
- ---
2
- name: arcgis-tables-forms
3
- description: Configure FeatureTable widget and FormTemplate with input elements. Use for displaying attribute data in tables, customizing edit forms, and configuring field inputs.
4
- ---
5
-
6
- # ArcGIS Tables & Forms
7
-
8
- Use this skill for configuring FeatureTable widgets and FormTemplate with various input elements.
9
-
10
- ## FeatureTable
11
-
12
- Display feature attributes in an interactive table.
13
-
14
- ### FeatureTable Component
15
-
16
- ```html
17
- <arcgis-map item-id="YOUR_WEBMAP_ID">
18
- <arcgis-zoom slot="top-left"></arcgis-zoom>
19
- </arcgis-map>
20
-
21
- <arcgis-feature-table reference-element="arcgis-map"></arcgis-feature-table>
22
-
23
- <script type="module">
24
- const map = document.querySelector("arcgis-map");
25
- const table = document.querySelector("arcgis-feature-table");
26
-
27
- await map.viewOnReady();
28
-
29
- // Set the layer for the table
30
- const layer = map.view.map.layers.find(l => l.type === "feature");
31
- table.layer = layer;
32
- </script>
33
- ```
34
-
35
- ### FeatureTable Widget (Core API)
36
-
37
- ```javascript
38
- import FeatureTable from "@arcgis/core/widgets/FeatureTable.js";
39
-
40
- const featureTable = new FeatureTable({
41
- view: view,
42
- layer: featureLayer,
43
- container: "tableDiv"
44
- });
45
- ```
46
-
47
- ### With Field Configuration
48
-
49
- ```javascript
50
- const featureTable = new FeatureTable({
51
- view: view,
52
- layer: featureLayer,
53
- container: "tableDiv",
54
- fieldConfigs: [
55
- {
56
- name: "name",
57
- label: "Name",
58
- direction: "asc" // Initial sort
59
- },
60
- {
61
- name: "category",
62
- label: "Category"
63
- },
64
- {
65
- name: "value",
66
- label: "Value",
67
- format: {
68
- digitSeparator: true,
69
- places: 2
70
- }
71
- },
72
- {
73
- name: "date_created",
74
- label: "Created",
75
- format: {
76
- dateFormat: "short-date"
77
- }
78
- }
79
- ]
80
- });
81
- ```
82
-
83
- ### FeatureTable Configuration
84
-
85
- ```javascript
86
- const featureTable = new FeatureTable({
87
- view: view,
88
- layer: featureLayer,
89
- container: "tableDiv",
90
-
91
- // Display options
92
- visibleElements: {
93
- header: true,
94
- menu: true,
95
- menuItems: {
96
- clearSelection: true,
97
- refreshData: true,
98
- toggleColumns: true,
99
- selectedRecordsShowAllToggle: true,
100
- selectedRecordsShowSelectedToggle: true,
101
- zoomToSelection: true
102
- },
103
- selectionColumn: true,
104
- columnMenus: true
105
- },
106
-
107
- // Table behavior
108
- multiSortEnabled: true,
109
- editingEnabled: true,
110
- highlightEnabled: true,
111
- attachmentsEnabled: true,
112
- relatedRecordsEnabled: true,
113
-
114
- // Pagination
115
- pageSize: 50,
116
-
117
- // Initial state
118
- filterGeometry: view.extent, // Only show features in view
119
- highlightOnRowSelectEnabled: true
120
- });
121
- ```
122
-
123
- ### Column Templates
124
-
125
- ```javascript
126
- import FieldColumnTemplate from "@arcgis/core/widgets/FeatureTable/support/FieldColumnTemplate.js";
127
-
128
- const featureTable = new FeatureTable({
129
- view: view,
130
- layer: featureLayer,
131
- tableTemplate: {
132
- columnTemplates: [
133
- new FieldColumnTemplate({
134
- fieldName: "name",
135
- label: "Name",
136
- sortable: true,
137
- initialSortPriority: 0,
138
- direction: "asc"
139
- }),
140
- new FieldColumnTemplate({
141
- fieldName: "status",
142
- label: "Status",
143
- menuConfig: {
144
- items: [{
145
- label: "Custom Action",
146
- iconClass: "esri-icon-settings",
147
- clickFunction: (event) => {
148
- console.log("Custom action on:", event.feature);
149
- }
150
- }]
151
- }
152
- }),
153
- new FieldColumnTemplate({
154
- fieldName: "value",
155
- label: "Value ($)",
156
- textAlign: "right",
157
- formatFunction: (info) => {
158
- return `$${info.value.toLocaleString()}`;
159
- }
160
- })
161
- ]
162
- }
163
- });
164
- ```
165
-
166
- ### Group Column Template
167
-
168
- ```javascript
169
- import GroupColumnTemplate from "@arcgis/core/widgets/FeatureTable/support/GroupColumnTemplate.js";
170
-
171
- const featureTable = new FeatureTable({
172
- view: view,
173
- layer: featureLayer,
174
- tableTemplate: {
175
- columnTemplates: [
176
- new GroupColumnTemplate({
177
- label: "Location",
178
- columnTemplates: [
179
- new FieldColumnTemplate({ fieldName: "city", label: "City" }),
180
- new FieldColumnTemplate({ fieldName: "state", label: "State" }),
181
- new FieldColumnTemplate({ fieldName: "country", label: "Country" })
182
- ]
183
- }),
184
- new GroupColumnTemplate({
185
- label: "Details",
186
- columnTemplates: [
187
- new FieldColumnTemplate({ fieldName: "name", label: "Name" }),
188
- new FieldColumnTemplate({ fieldName: "type", label: "Type" })
189
- ]
190
- })
191
- ]
192
- }
193
- });
194
- ```
195
-
196
- ### FeatureTable Events
197
-
198
- ```javascript
199
- // Row selection
200
- featureTable.on("selection-change", (event) => {
201
- console.log("Added:", event.added);
202
- console.log("Removed:", event.removed);
203
-
204
- // Get all selected features
205
- const selectedFeatures = featureTable.highlightIds.toArray();
206
- });
207
-
208
- // Row click (double-click to zoom)
209
- featureTable.viewModel.on("row-highlight-change", (event) => {
210
- if (event.feature) {
211
- view.goTo(event.feature.geometry);
212
- }
213
- });
214
-
215
- // Editing complete
216
- featureTable.on("edit-complete", (event) => {
217
- console.log("Edited feature:", event.feature);
218
- console.log("Updated attributes:", event.attributes);
219
- });
220
- ```
221
-
222
- ### Programmatic Selection
223
-
224
- ```javascript
225
- // Select by ObjectIDs
226
- featureTable.highlightIds.add(123);
227
- featureTable.highlightIds.addMany([124, 125, 126]);
228
-
229
- // Clear selection
230
- featureTable.highlightIds.removeAll();
231
-
232
- // Select from query
233
- const results = await featureLayer.queryObjectIds({
234
- where: "status = 'active'"
235
- });
236
- featureTable.highlightIds.addMany(results);
237
- ```
238
-
239
- ### Filter and Refresh
240
-
241
- ```javascript
242
- // Filter by geometry
243
- featureTable.filterGeometry = view.extent;
244
-
245
- // Filter by expression
246
- featureTable.layer.definitionExpression = "category = 'A'";
247
-
248
- // Refresh data
249
- featureTable.refresh();
250
-
251
- // Clear filters
252
- featureTable.filterGeometry = null;
253
- featureTable.layer.definitionExpression = null;
254
- ```
255
-
256
- ### Sync with Map Selection
257
-
258
- ```javascript
259
- // Map click selects in table
260
- view.on("click", async (event) => {
261
- const response = await view.hitTest(event);
262
- const feature = response.results.find(r => r.layer === featureLayer);
263
-
264
- if (feature) {
265
- featureTable.highlightIds.removeAll();
266
- featureTable.highlightIds.add(feature.graphic.attributes.OBJECTID);
267
- }
268
- });
269
-
270
- // Table selection highlights on map
271
- featureTable.on("selection-change", async (event) => {
272
- const layerView = await view.whenLayerView(featureLayer);
273
-
274
- if (highlightHandle) {
275
- highlightHandle.remove();
276
- }
277
-
278
- const objectIds = featureTable.highlightIds.toArray();
279
- if (objectIds.length > 0) {
280
- const query = featureLayer.createQuery();
281
- query.objectIds = objectIds;
282
- const results = await featureLayer.queryFeatures(query);
283
- highlightHandle = layerView.highlight(results.features);
284
- }
285
- });
286
- ```
287
-
288
- ## FormTemplate
289
-
290
- Configure edit forms for features.
291
-
292
- ### Basic FormTemplate
293
-
294
- ```javascript
295
- import FormTemplate from "@arcgis/core/form/FormTemplate.js";
296
-
297
- const formTemplate = new FormTemplate({
298
- title: "Edit Feature",
299
- description: "Update the feature attributes",
300
- elements: [
301
- {
302
- type: "field",
303
- fieldName: "name",
304
- label: "Name"
305
- },
306
- {
307
- type: "field",
308
- fieldName: "category",
309
- label: "Category"
310
- },
311
- {
312
- type: "field",
313
- fieldName: "description",
314
- label: "Description"
315
- }
316
- ]
317
- });
318
-
319
- featureLayer.formTemplate = formTemplate;
320
- ```
321
-
322
- ### Field Elements
323
-
324
- ```javascript
325
- import FieldElement from "@arcgis/core/form/elements/FieldElement.js";
326
-
327
- const fieldElement = new FieldElement({
328
- fieldName: "name",
329
- label: "Name",
330
- description: "Enter the feature name",
331
- hint: "Required field",
332
- requiredExpression: "true",
333
- editableExpression: "$feature.status != 'locked'",
334
- visibilityExpression: "$feature.type != 'hidden'"
335
- });
336
- ```
337
-
338
- ### Group Elements
339
-
340
- ```javascript
341
- import GroupElement from "@arcgis/core/form/elements/GroupElement.js";
342
-
343
- const formTemplate = new FormTemplate({
344
- elements: [
345
- new GroupElement({
346
- label: "Basic Information",
347
- description: "Enter basic details",
348
- elements: [
349
- { type: "field", fieldName: "name", label: "Name" },
350
- { type: "field", fieldName: "type", label: "Type" }
351
- ]
352
- }),
353
- new GroupElement({
354
- label: "Location",
355
- initialState: "collapsed", // expanded, collapsed
356
- elements: [
357
- { type: "field", fieldName: "address", label: "Address" },
358
- { type: "field", fieldName: "city", label: "City" },
359
- { type: "field", fieldName: "state", label: "State" }
360
- ]
361
- })
362
- ]
363
- });
364
- ```
365
-
366
- ### Text Elements
367
-
368
- ```javascript
369
- import TextElement from "@arcgis/core/form/elements/TextElement.js";
370
-
371
- const formTemplate = new FormTemplate({
372
- elements: [
373
- new TextElement({
374
- type: "text",
375
- text: "<h3>Important Instructions</h3><p>Please fill out all required fields.</p>"
376
- }),
377
- { type: "field", fieldName: "name", label: "Name" },
378
- new TextElement({
379
- text: "<hr><small>Fields below are optional</small>"
380
- }),
381
- { type: "field", fieldName: "notes", label: "Notes" }
382
- ]
383
- });
384
- ```
385
-
386
- ### Relationship Elements
387
-
388
- ```javascript
389
- import RelationshipElement from "@arcgis/core/form/elements/RelationshipElement.js";
390
-
391
- const formTemplate = new FormTemplate({
392
- elements: [
393
- { type: "field", fieldName: "name", label: "Name" },
394
- new RelationshipElement({
395
- relationshipId: 0,
396
- label: "Related Inspections",
397
- description: "View and manage related inspection records",
398
- displayCount: 5,
399
- orderByFields: [{
400
- field: "inspection_date",
401
- order: "desc"
402
- }],
403
- editableExpression: "true"
404
- })
405
- ]
406
- });
407
- ```
408
-
409
- ## Input Types
410
-
411
- ### TextBox Input
412
-
413
- ```javascript
414
- {
415
- type: "field",
416
- fieldName: "name",
417
- label: "Name",
418
- input: {
419
- type: "text-box",
420
- maxLength: 100,
421
- minLength: 1
422
- }
423
- }
424
- ```
425
-
426
- ### TextArea Input
427
-
428
- ```javascript
429
- {
430
- type: "field",
431
- fieldName: "description",
432
- label: "Description",
433
- input: {
434
- type: "text-area",
435
- maxLength: 1000,
436
- minLength: 0
437
- }
438
- }
439
- ```
440
-
441
- ### ComboBox Input
442
-
443
- ```javascript
444
- {
445
- type: "field",
446
- fieldName: "category",
447
- label: "Category",
448
- input: {
449
- type: "combo-box",
450
- showNoValueOption: true,
451
- noValueOptionLabel: "Select a category..."
452
- }
453
- }
454
-
455
- // Works with coded value domains
456
- // Domain values automatically populate the combo box
457
- ```
458
-
459
- ### Radio Buttons Input
460
-
461
- ```javascript
462
- {
463
- type: "field",
464
- fieldName: "priority",
465
- label: "Priority",
466
- input: {
467
- type: "radio-buttons",
468
- showNoValueOption: false
469
- }
470
- }
471
- ```
472
-
473
- ### Switch Input
474
-
475
- ```javascript
476
- {
477
- type: "field",
478
- fieldName: "is_active",
479
- label: "Active",
480
- input: {
481
- type: "switch",
482
- offValue: 0,
483
- onValue: 1
484
- }
485
- }
486
- ```
487
-
488
- ### DatePicker Input
489
-
490
- ```javascript
491
- {
492
- type: "field",
493
- fieldName: "start_date",
494
- label: "Start Date",
495
- input: {
496
- type: "date-picker",
497
- min: new Date("2020-01-01"),
498
- max: new Date("2030-12-31"),
499
- includeTime: false
500
- }
501
- }
502
- ```
503
-
504
- ### DateTimePicker Input
505
-
506
- ```javascript
507
- {
508
- type: "field",
509
- fieldName: "event_datetime",
510
- label: "Event Date/Time",
511
- input: {
512
- type: "datetime-picker",
513
- min: new Date("2020-01-01T00:00:00"),
514
- max: new Date("2030-12-31T23:59:59"),
515
- includeTime: true
516
- }
517
- }
518
- ```
519
-
520
- ### TimePicker Input
521
-
522
- ```javascript
523
- {
524
- type: "field",
525
- fieldName: "event_time",
526
- label: "Event Time",
527
- input: {
528
- type: "time-picker"
529
- }
530
- }
531
- ```
532
-
533
- ### Barcode Scanner Input
534
-
535
- ```javascript
536
- {
537
- type: "field",
538
- fieldName: "barcode",
539
- label: "Barcode",
540
- input: {
541
- type: "barcode-scanner"
542
- }
543
- }
544
- ```
545
-
546
- ## Expression-Based Configuration
547
-
548
- ### Visibility Expressions
549
-
550
- ```javascript
551
- const formTemplate = new FormTemplate({
552
- expressionInfos: [
553
- {
554
- name: "show-commercial-fields",
555
- expression: "$feature.property_type == 'commercial'"
556
- },
557
- {
558
- name: "show-residential-fields",
559
- expression: "$feature.property_type == 'residential'"
560
- }
561
- ],
562
- elements: [
563
- { type: "field", fieldName: "property_type", label: "Property Type" },
564
- {
565
- type: "group",
566
- label: "Commercial Details",
567
- visibilityExpression: "show-commercial-fields",
568
- elements: [
569
- { type: "field", fieldName: "business_name", label: "Business Name" },
570
- { type: "field", fieldName: "num_employees", label: "Employees" }
571
- ]
572
- },
573
- {
574
- type: "group",
575
- label: "Residential Details",
576
- visibilityExpression: "show-residential-fields",
577
- elements: [
578
- { type: "field", fieldName: "num_bedrooms", label: "Bedrooms" },
579
- { type: "field", fieldName: "num_bathrooms", label: "Bathrooms" }
580
- ]
581
- }
582
- ]
583
- });
584
- ```
585
-
586
- ### Required Expressions
587
-
588
- ```javascript
589
- {
590
- type: "field",
591
- fieldName: "inspection_notes",
592
- label: "Inspection Notes",
593
- requiredExpression: "$feature.inspection_result == 'failed'"
594
- }
595
- ```
596
-
597
- ### Editable Expressions
598
-
599
- ```javascript
600
- {
601
- type: "field",
602
- fieldName: "approved_by",
603
- label: "Approved By",
604
- editableExpression: "$feature.status == 'pending'"
605
- }
606
- ```
607
-
608
- ## FeatureForm Widget
609
-
610
- Widget for editing feature attributes.
611
-
612
- ```javascript
613
- import FeatureForm from "@arcgis/core/widgets/FeatureForm.js";
614
-
615
- const featureForm = new FeatureForm({
616
- container: "formDiv",
617
- layer: featureLayer,
618
- formTemplate: formTemplate
619
- });
620
-
621
- // Set feature to edit
622
- featureForm.feature = selectedGraphic;
623
-
624
- // Listen for submit
625
- featureForm.on("submit", () => {
626
- if (featureForm.feature) {
627
- const updated = featureForm.getValues();
628
-
629
- featureLayer.applyEdits({
630
- updateFeatures: [{
631
- attributes: {
632
- ...featureForm.feature.attributes,
633
- ...updated
634
- },
635
- geometry: featureForm.feature.geometry
636
- }]
637
- });
638
- }
639
- });
640
-
641
- // Handle value changes
642
- featureForm.on("value-change", (event) => {
643
- console.log(`${event.fieldName} changed to ${event.value}`);
644
- });
645
- ```
646
-
647
- ## AttributeTableTemplate
648
-
649
- Configure attribute table in Editor widget.
650
-
651
- ```javascript
652
- import AttributeTableTemplate from "@arcgis/core/widgets/Editor/support/AttributeTableTemplate.js";
653
- import AttributeTableFieldElement from "@arcgis/core/widgets/Editor/support/AttributeTableFieldElement.js";
654
-
655
- const tableTemplate = new AttributeTableTemplate({
656
- elements: [
657
- new AttributeTableFieldElement({
658
- fieldName: "name",
659
- label: "Name",
660
- editable: true
661
- }),
662
- new AttributeTableFieldElement({
663
- fieldName: "status",
664
- label: "Status",
665
- editable: true
666
- })
667
- ]
668
- });
669
- ```
670
-
671
- ## Editor Widget Integration
672
-
673
- ```javascript
674
- import Editor from "@arcgis/core/widgets/Editor.js";
675
-
676
- const editor = new Editor({
677
- view: view,
678
- layerInfos: [{
679
- layer: featureLayer,
680
- formTemplate: formTemplate,
681
- enabled: true,
682
- addEnabled: true,
683
- updateEnabled: true,
684
- deleteEnabled: true
685
- }]
686
- });
687
-
688
- view.ui.add(editor, "top-right");
689
- ```
690
-
691
- ## Common Patterns
692
-
693
- ### Complete Form Setup
694
-
695
- ```javascript
696
- const formTemplate = new FormTemplate({
697
- title: "Property Information",
698
- description: "Enter property details",
699
- preserveFieldValuesWhenHidden: true,
700
- expressionInfos: [
701
- {
702
- name: "is-commercial",
703
- expression: "$feature.type == 'commercial'"
704
- }
705
- ],
706
- elements: [
707
- // Header text
708
- {
709
- type: "text",
710
- text: "<b>Basic Information</b>"
711
- },
712
- // Required field
713
- {
714
- type: "field",
715
- fieldName: "name",
716
- label: "Property Name",
717
- requiredExpression: "true",
718
- input: { type: "text-box", maxLength: 100 }
719
- },
720
- // Dropdown
721
- {
722
- type: "field",
723
- fieldName: "type",
724
- label: "Property Type",
725
- input: { type: "combo-box" }
726
- },
727
- // Conditional group
728
- {
729
- type: "group",
730
- label: "Commercial Details",
731
- visibilityExpression: "is-commercial",
732
- elements: [
733
- { type: "field", fieldName: "business_type", label: "Business Type" },
734
- { type: "field", fieldName: "sqft", label: "Square Footage" }
735
- ]
736
- },
737
- // Date field
738
- {
739
- type: "field",
740
- fieldName: "inspection_date",
741
- label: "Last Inspection",
742
- input: { type: "date-picker" }
743
- },
744
- // Long text
745
- {
746
- type: "field",
747
- fieldName: "notes",
748
- label: "Notes",
749
- input: { type: "text-area", maxLength: 500 }
750
- }
751
- ]
752
- });
753
- ```
754
-
755
- ### FeatureTable with Editing
756
-
757
- ```javascript
758
- const featureTable = new FeatureTable({
759
- view: view,
760
- layer: featureLayer,
761
- container: "tableDiv",
762
- editingEnabled: true,
763
- fieldConfigs: [
764
- { name: "name", label: "Name", editable: true },
765
- { name: "status", label: "Status", editable: true },
766
- { name: "created_date", label: "Created", editable: false }
767
- ]
768
- });
769
-
770
- featureTable.on("edit-complete", async (event) => {
771
- console.log("Edit saved:", event.feature.attributes);
772
-
773
- // Refresh related data
774
- await featureLayer.refresh();
775
- });
776
- ```
777
-
778
- ### Responsive Table Layout
779
-
780
- ```javascript
781
- const featureTable = new FeatureTable({
782
- view: view,
783
- layer: featureLayer,
784
- container: "tableDiv",
785
- autoRefreshEnabled: true,
786
- pageSize: 25
787
- });
788
-
789
- // Resize handling
790
- window.addEventListener("resize", () => {
791
- featureTable.refresh();
792
- });
793
-
794
- // Toggle visibility
795
- function toggleTable(visible) {
796
- document.getElementById("tableDiv").style.display = visible ? "block" : "none";
797
- if (visible) {
798
- featureTable.refresh();
799
- }
800
- }
801
- ```
802
-
803
- ## TypeScript Usage
804
-
805
- Form elements use autocasting with `type` properties. For TypeScript safety, use `as const`:
806
-
807
- ```typescript
808
- // Use 'as const' for type safety in form templates
809
- const formTemplate = {
810
- title: "Edit Feature",
811
- elements: [
812
- {
813
- type: "field",
814
- fieldName: "name",
815
- label: "Name"
816
- },
817
- {
818
- type: "group",
819
- label: "Address",
820
- elements: [
821
- { type: "field", fieldName: "street" },
822
- { type: "field", fieldName: "city" }
823
- ]
824
- }
825
- ]
826
- } as const;
827
-
828
- // For input types
829
- const formElement = {
830
- type: "field",
831
- fieldName: "status",
832
- input: { type: "combo-box" }
833
- } as const;
834
- ```
835
-
836
- > **Tip:** See [arcgis-core-maps skill](../arcgis-core-maps/SKILL.md) for detailed guidance on autocasting vs explicit classes.
837
-
838
- ## Common Pitfalls
839
-
840
- 1. **Field Names Must Match**: fieldName must exactly match layer field
841
- ```javascript
842
- // Layer has field "PropertyName"
843
- { fieldName: "PropertyName" } // Correct
844
- { fieldName: "propertyname" } // Wrong - case sensitive
845
- ```
846
-
847
- 2. **Coded Value Domains**: ComboBox auto-populates from domain
848
- ```javascript
849
- // If field has coded value domain, values come from domain
850
- { type: "field", fieldName: "status", input: { type: "combo-box" } }
851
- // Dropdown shows domain values automatically
852
- ```
853
-
854
- 3. **Expression Names**: Reference expressions by name string
855
- ```javascript
856
- expressionInfos: [{ name: "my-expr", expression: "..." }],
857
- elements: [{
858
- visibilityExpression: "my-expr" // String reference
859
- }]
860
- ```
861
-
862
- 4. **Layer Must Be Editable**: For edit features to work
863
- ```javascript
864
- // Layer capabilities must include editing
865
- if (layer.capabilities.editing.supportsUpdateByOthers) {
866
- featureTable.editingEnabled = true;
867
- }
868
- ```
869
-
870
- 5. **Container Size**: Table needs explicit height
871
- ```css
872
- #tableDiv {
873
- height: 400px; /* Required */
874
- width: 100%;
875
- }
876
- ```
877
-
1
+ ---
2
+ name: arcgis-tables-forms
3
+ description: Configure FeatureTable widget and FormTemplate with input elements. Use for displaying attribute data in tables, customizing edit forms, and configuring field inputs.
4
+ ---
5
+
6
+ # ArcGIS Tables & Forms
7
+
8
+ Use this skill for configuring FeatureTable widgets and FormTemplate with various input elements.
9
+
10
+ ## FeatureTable
11
+
12
+ Display feature attributes in an interactive table.
13
+
14
+ ### FeatureTable Component
15
+
16
+ ```html
17
+ <arcgis-map item-id="YOUR_WEBMAP_ID">
18
+ <arcgis-zoom slot="top-left"></arcgis-zoom>
19
+ </arcgis-map>
20
+
21
+ <arcgis-feature-table reference-element="arcgis-map"></arcgis-feature-table>
22
+
23
+ <script type="module">
24
+ const map = document.querySelector("arcgis-map");
25
+ const table = document.querySelector("arcgis-feature-table");
26
+
27
+ await map.viewOnReady();
28
+
29
+ // Set the layer for the table
30
+ const layer = map.view.map.layers.find(l => l.type === "feature");
31
+ table.layer = layer;
32
+ </script>
33
+ ```
34
+
35
+ ### FeatureTable Widget (Core API)
36
+
37
+ ```javascript
38
+ import FeatureTable from "@arcgis/core/widgets/FeatureTable.js";
39
+
40
+ const featureTable = new FeatureTable({
41
+ view: view,
42
+ layer: featureLayer,
43
+ container: "tableDiv"
44
+ });
45
+ ```
46
+
47
+ ### With Field Configuration
48
+
49
+ ```javascript
50
+ const featureTable = new FeatureTable({
51
+ view: view,
52
+ layer: featureLayer,
53
+ container: "tableDiv",
54
+ fieldConfigs: [
55
+ {
56
+ name: "name",
57
+ label: "Name",
58
+ direction: "asc" // Initial sort
59
+ },
60
+ {
61
+ name: "category",
62
+ label: "Category"
63
+ },
64
+ {
65
+ name: "value",
66
+ label: "Value",
67
+ format: {
68
+ digitSeparator: true,
69
+ places: 2
70
+ }
71
+ },
72
+ {
73
+ name: "date_created",
74
+ label: "Created",
75
+ format: {
76
+ dateFormat: "short-date"
77
+ }
78
+ }
79
+ ]
80
+ });
81
+ ```
82
+
83
+ ### FeatureTable Configuration
84
+
85
+ ```javascript
86
+ const featureTable = new FeatureTable({
87
+ view: view,
88
+ layer: featureLayer,
89
+ container: "tableDiv",
90
+
91
+ // Display options
92
+ visibleElements: {
93
+ header: true,
94
+ menu: true,
95
+ menuItems: {
96
+ clearSelection: true,
97
+ refreshData: true,
98
+ toggleColumns: true,
99
+ selectedRecordsShowAllToggle: true,
100
+ selectedRecordsShowSelectedToggle: true,
101
+ zoomToSelection: true
102
+ },
103
+ selectionColumn: true,
104
+ columnMenus: true
105
+ },
106
+
107
+ // Table behavior
108
+ multiSortEnabled: true,
109
+ editingEnabled: true,
110
+ highlightEnabled: true,
111
+ attachmentsEnabled: true,
112
+ relatedRecordsEnabled: true,
113
+
114
+ // Pagination
115
+ pageSize: 50,
116
+
117
+ // Initial state
118
+ filterGeometry: view.extent, // Only show features in view
119
+ highlightOnRowSelectEnabled: true
120
+ });
121
+ ```
122
+
123
+ ### Column Templates
124
+
125
+ ```javascript
126
+ import FieldColumnTemplate from "@arcgis/core/widgets/FeatureTable/support/FieldColumnTemplate.js";
127
+
128
+ const featureTable = new FeatureTable({
129
+ view: view,
130
+ layer: featureLayer,
131
+ tableTemplate: {
132
+ columnTemplates: [
133
+ new FieldColumnTemplate({
134
+ fieldName: "name",
135
+ label: "Name",
136
+ sortable: true,
137
+ initialSortPriority: 0,
138
+ direction: "asc"
139
+ }),
140
+ new FieldColumnTemplate({
141
+ fieldName: "status",
142
+ label: "Status",
143
+ menuConfig: {
144
+ items: [{
145
+ label: "Custom Action",
146
+ iconClass: "esri-icon-settings",
147
+ clickFunction: (event) => {
148
+ console.log("Custom action on:", event.feature);
149
+ }
150
+ }]
151
+ }
152
+ }),
153
+ new FieldColumnTemplate({
154
+ fieldName: "value",
155
+ label: "Value ($)",
156
+ textAlign: "right",
157
+ formatFunction: (info) => {
158
+ return `$${info.value.toLocaleString()}`;
159
+ }
160
+ })
161
+ ]
162
+ }
163
+ });
164
+ ```
165
+
166
+ ### Group Column Template
167
+
168
+ ```javascript
169
+ import GroupColumnTemplate from "@arcgis/core/widgets/FeatureTable/support/GroupColumnTemplate.js";
170
+
171
+ const featureTable = new FeatureTable({
172
+ view: view,
173
+ layer: featureLayer,
174
+ tableTemplate: {
175
+ columnTemplates: [
176
+ new GroupColumnTemplate({
177
+ label: "Location",
178
+ columnTemplates: [
179
+ new FieldColumnTemplate({ fieldName: "city", label: "City" }),
180
+ new FieldColumnTemplate({ fieldName: "state", label: "State" }),
181
+ new FieldColumnTemplate({ fieldName: "country", label: "Country" })
182
+ ]
183
+ }),
184
+ new GroupColumnTemplate({
185
+ label: "Details",
186
+ columnTemplates: [
187
+ new FieldColumnTemplate({ fieldName: "name", label: "Name" }),
188
+ new FieldColumnTemplate({ fieldName: "type", label: "Type" })
189
+ ]
190
+ })
191
+ ]
192
+ }
193
+ });
194
+ ```
195
+
196
+ ### FeatureTable Events
197
+
198
+ ```javascript
199
+ // Row selection
200
+ featureTable.on("selection-change", (event) => {
201
+ console.log("Added:", event.added);
202
+ console.log("Removed:", event.removed);
203
+
204
+ // Get all selected features
205
+ const selectedFeatures = featureTable.highlightIds.toArray();
206
+ });
207
+
208
+ // Row click (double-click to zoom)
209
+ featureTable.viewModel.on("row-highlight-change", (event) => {
210
+ if (event.feature) {
211
+ view.goTo(event.feature.geometry);
212
+ }
213
+ });
214
+
215
+ // Editing complete
216
+ featureTable.on("edit-complete", (event) => {
217
+ console.log("Edited feature:", event.feature);
218
+ console.log("Updated attributes:", event.attributes);
219
+ });
220
+ ```
221
+
222
+ ### Programmatic Selection
223
+
224
+ ```javascript
225
+ // Select by ObjectIDs
226
+ featureTable.highlightIds.add(123);
227
+ featureTable.highlightIds.addMany([124, 125, 126]);
228
+
229
+ // Clear selection
230
+ featureTable.highlightIds.removeAll();
231
+
232
+ // Select from query
233
+ const results = await featureLayer.queryObjectIds({
234
+ where: "status = 'active'"
235
+ });
236
+ featureTable.highlightIds.addMany(results);
237
+ ```
238
+
239
+ ### Filter and Refresh
240
+
241
+ ```javascript
242
+ // Filter by geometry
243
+ featureTable.filterGeometry = view.extent;
244
+
245
+ // Filter by expression
246
+ featureTable.layer.definitionExpression = "category = 'A'";
247
+
248
+ // Refresh data
249
+ featureTable.refresh();
250
+
251
+ // Clear filters
252
+ featureTable.filterGeometry = null;
253
+ featureTable.layer.definitionExpression = null;
254
+ ```
255
+
256
+ ### Sync with Map Selection
257
+
258
+ ```javascript
259
+ // Map click selects in table
260
+ view.on("click", async (event) => {
261
+ const response = await view.hitTest(event);
262
+ const feature = response.results.find(r => r.layer === featureLayer);
263
+
264
+ if (feature) {
265
+ featureTable.highlightIds.removeAll();
266
+ featureTable.highlightIds.add(feature.graphic.attributes.OBJECTID);
267
+ }
268
+ });
269
+
270
+ // Table selection highlights on map
271
+ featureTable.on("selection-change", async (event) => {
272
+ const layerView = await view.whenLayerView(featureLayer);
273
+
274
+ if (highlightHandle) {
275
+ highlightHandle.remove();
276
+ }
277
+
278
+ const objectIds = featureTable.highlightIds.toArray();
279
+ if (objectIds.length > 0) {
280
+ const query = featureLayer.createQuery();
281
+ query.objectIds = objectIds;
282
+ const results = await featureLayer.queryFeatures(query);
283
+ highlightHandle = layerView.highlight(results.features);
284
+ }
285
+ });
286
+ ```
287
+
288
+ ## FormTemplate
289
+
290
+ Configure edit forms for features.
291
+
292
+ ### Basic FormTemplate
293
+
294
+ ```javascript
295
+ import FormTemplate from "@arcgis/core/form/FormTemplate.js";
296
+
297
+ const formTemplate = new FormTemplate({
298
+ title: "Edit Feature",
299
+ description: "Update the feature attributes",
300
+ elements: [
301
+ {
302
+ type: "field",
303
+ fieldName: "name",
304
+ label: "Name"
305
+ },
306
+ {
307
+ type: "field",
308
+ fieldName: "category",
309
+ label: "Category"
310
+ },
311
+ {
312
+ type: "field",
313
+ fieldName: "description",
314
+ label: "Description"
315
+ }
316
+ ]
317
+ });
318
+
319
+ featureLayer.formTemplate = formTemplate;
320
+ ```
321
+
322
+ ### Field Elements
323
+
324
+ ```javascript
325
+ import FieldElement from "@arcgis/core/form/elements/FieldElement.js";
326
+
327
+ const fieldElement = new FieldElement({
328
+ fieldName: "name",
329
+ label: "Name",
330
+ description: "Enter the feature name",
331
+ hint: "Required field",
332
+ requiredExpression: "true",
333
+ editableExpression: "$feature.status != 'locked'",
334
+ visibilityExpression: "$feature.type != 'hidden'"
335
+ });
336
+ ```
337
+
338
+ ### Group Elements
339
+
340
+ ```javascript
341
+ import GroupElement from "@arcgis/core/form/elements/GroupElement.js";
342
+
343
+ const formTemplate = new FormTemplate({
344
+ elements: [
345
+ new GroupElement({
346
+ label: "Basic Information",
347
+ description: "Enter basic details",
348
+ elements: [
349
+ { type: "field", fieldName: "name", label: "Name" },
350
+ { type: "field", fieldName: "type", label: "Type" }
351
+ ]
352
+ }),
353
+ new GroupElement({
354
+ label: "Location",
355
+ initialState: "collapsed", // expanded, collapsed
356
+ elements: [
357
+ { type: "field", fieldName: "address", label: "Address" },
358
+ { type: "field", fieldName: "city", label: "City" },
359
+ { type: "field", fieldName: "state", label: "State" }
360
+ ]
361
+ })
362
+ ]
363
+ });
364
+ ```
365
+
366
+ ### Text Elements
367
+
368
+ ```javascript
369
+ import TextElement from "@arcgis/core/form/elements/TextElement.js";
370
+
371
+ const formTemplate = new FormTemplate({
372
+ elements: [
373
+ new TextElement({
374
+ type: "text",
375
+ text: "<h3>Important Instructions</h3><p>Please fill out all required fields.</p>"
376
+ }),
377
+ { type: "field", fieldName: "name", label: "Name" },
378
+ new TextElement({
379
+ text: "<hr><small>Fields below are optional</small>"
380
+ }),
381
+ { type: "field", fieldName: "notes", label: "Notes" }
382
+ ]
383
+ });
384
+ ```
385
+
386
+ ### Relationship Elements
387
+
388
+ ```javascript
389
+ import RelationshipElement from "@arcgis/core/form/elements/RelationshipElement.js";
390
+
391
+ const formTemplate = new FormTemplate({
392
+ elements: [
393
+ { type: "field", fieldName: "name", label: "Name" },
394
+ new RelationshipElement({
395
+ relationshipId: 0,
396
+ label: "Related Inspections",
397
+ description: "View and manage related inspection records",
398
+ displayCount: 5,
399
+ orderByFields: [{
400
+ field: "inspection_date",
401
+ order: "desc"
402
+ }],
403
+ editableExpression: "true"
404
+ })
405
+ ]
406
+ });
407
+ ```
408
+
409
+ ## Input Types
410
+
411
+ ### TextBox Input
412
+
413
+ ```javascript
414
+ {
415
+ type: "field",
416
+ fieldName: "name",
417
+ label: "Name",
418
+ input: {
419
+ type: "text-box",
420
+ maxLength: 100,
421
+ minLength: 1
422
+ }
423
+ }
424
+ ```
425
+
426
+ ### TextArea Input
427
+
428
+ ```javascript
429
+ {
430
+ type: "field",
431
+ fieldName: "description",
432
+ label: "Description",
433
+ input: {
434
+ type: "text-area",
435
+ maxLength: 1000,
436
+ minLength: 0
437
+ }
438
+ }
439
+ ```
440
+
441
+ ### ComboBox Input
442
+
443
+ ```javascript
444
+ {
445
+ type: "field",
446
+ fieldName: "category",
447
+ label: "Category",
448
+ input: {
449
+ type: "combo-box",
450
+ showNoValueOption: true,
451
+ noValueOptionLabel: "Select a category..."
452
+ }
453
+ }
454
+
455
+ // Works with coded value domains
456
+ // Domain values automatically populate the combo box
457
+ ```
458
+
459
+ ### Radio Buttons Input
460
+
461
+ ```javascript
462
+ {
463
+ type: "field",
464
+ fieldName: "priority",
465
+ label: "Priority",
466
+ input: {
467
+ type: "radio-buttons",
468
+ showNoValueOption: false
469
+ }
470
+ }
471
+ ```
472
+
473
+ ### Switch Input
474
+
475
+ ```javascript
476
+ {
477
+ type: "field",
478
+ fieldName: "is_active",
479
+ label: "Active",
480
+ input: {
481
+ type: "switch",
482
+ offValue: 0,
483
+ onValue: 1
484
+ }
485
+ }
486
+ ```
487
+
488
+ ### DatePicker Input
489
+
490
+ ```javascript
491
+ {
492
+ type: "field",
493
+ fieldName: "start_date",
494
+ label: "Start Date",
495
+ input: {
496
+ type: "date-picker",
497
+ min: new Date("2020-01-01"),
498
+ max: new Date("2030-12-31"),
499
+ includeTime: false
500
+ }
501
+ }
502
+ ```
503
+
504
+ ### DateTimePicker Input
505
+
506
+ ```javascript
507
+ {
508
+ type: "field",
509
+ fieldName: "event_datetime",
510
+ label: "Event Date/Time",
511
+ input: {
512
+ type: "datetime-picker",
513
+ min: new Date("2020-01-01T00:00:00"),
514
+ max: new Date("2030-12-31T23:59:59"),
515
+ includeTime: true
516
+ }
517
+ }
518
+ ```
519
+
520
+ ### TimePicker Input
521
+
522
+ ```javascript
523
+ {
524
+ type: "field",
525
+ fieldName: "event_time",
526
+ label: "Event Time",
527
+ input: {
528
+ type: "time-picker"
529
+ }
530
+ }
531
+ ```
532
+
533
+ ### Barcode Scanner Input
534
+
535
+ ```javascript
536
+ {
537
+ type: "field",
538
+ fieldName: "barcode",
539
+ label: "Barcode",
540
+ input: {
541
+ type: "barcode-scanner"
542
+ }
543
+ }
544
+ ```
545
+
546
+ ## Expression-Based Configuration
547
+
548
+ ### Visibility Expressions
549
+
550
+ ```javascript
551
+ const formTemplate = new FormTemplate({
552
+ expressionInfos: [
553
+ {
554
+ name: "show-commercial-fields",
555
+ expression: "$feature.property_type == 'commercial'"
556
+ },
557
+ {
558
+ name: "show-residential-fields",
559
+ expression: "$feature.property_type == 'residential'"
560
+ }
561
+ ],
562
+ elements: [
563
+ { type: "field", fieldName: "property_type", label: "Property Type" },
564
+ {
565
+ type: "group",
566
+ label: "Commercial Details",
567
+ visibilityExpression: "show-commercial-fields",
568
+ elements: [
569
+ { type: "field", fieldName: "business_name", label: "Business Name" },
570
+ { type: "field", fieldName: "num_employees", label: "Employees" }
571
+ ]
572
+ },
573
+ {
574
+ type: "group",
575
+ label: "Residential Details",
576
+ visibilityExpression: "show-residential-fields",
577
+ elements: [
578
+ { type: "field", fieldName: "num_bedrooms", label: "Bedrooms" },
579
+ { type: "field", fieldName: "num_bathrooms", label: "Bathrooms" }
580
+ ]
581
+ }
582
+ ]
583
+ });
584
+ ```
585
+
586
+ ### Required Expressions
587
+
588
+ ```javascript
589
+ {
590
+ type: "field",
591
+ fieldName: "inspection_notes",
592
+ label: "Inspection Notes",
593
+ requiredExpression: "$feature.inspection_result == 'failed'"
594
+ }
595
+ ```
596
+
597
+ ### Editable Expressions
598
+
599
+ ```javascript
600
+ {
601
+ type: "field",
602
+ fieldName: "approved_by",
603
+ label: "Approved By",
604
+ editableExpression: "$feature.status == 'pending'"
605
+ }
606
+ ```
607
+
608
+ ## FeatureForm Widget
609
+
610
+ Widget for editing feature attributes.
611
+
612
+ ```javascript
613
+ import FeatureForm from "@arcgis/core/widgets/FeatureForm.js";
614
+
615
+ const featureForm = new FeatureForm({
616
+ container: "formDiv",
617
+ layer: featureLayer,
618
+ formTemplate: formTemplate
619
+ });
620
+
621
+ // Set feature to edit
622
+ featureForm.feature = selectedGraphic;
623
+
624
+ // Listen for submit
625
+ featureForm.on("submit", () => {
626
+ if (featureForm.feature) {
627
+ const updated = featureForm.getValues();
628
+
629
+ featureLayer.applyEdits({
630
+ updateFeatures: [{
631
+ attributes: {
632
+ ...featureForm.feature.attributes,
633
+ ...updated
634
+ },
635
+ geometry: featureForm.feature.geometry
636
+ }]
637
+ });
638
+ }
639
+ });
640
+
641
+ // Handle value changes
642
+ featureForm.on("value-change", (event) => {
643
+ console.log(`${event.fieldName} changed to ${event.value}`);
644
+ });
645
+ ```
646
+
647
+ ## AttributeTableTemplate
648
+
649
+ Configure attribute table in Editor widget.
650
+
651
+ ```javascript
652
+ import AttributeTableTemplate from "@arcgis/core/widgets/Editor/support/AttributeTableTemplate.js";
653
+ import AttributeTableFieldElement from "@arcgis/core/widgets/Editor/support/AttributeTableFieldElement.js";
654
+
655
+ const tableTemplate = new AttributeTableTemplate({
656
+ elements: [
657
+ new AttributeTableFieldElement({
658
+ fieldName: "name",
659
+ label: "Name",
660
+ editable: true
661
+ }),
662
+ new AttributeTableFieldElement({
663
+ fieldName: "status",
664
+ label: "Status",
665
+ editable: true
666
+ })
667
+ ]
668
+ });
669
+ ```
670
+
671
+ ## Editor Widget Integration
672
+
673
+ ```javascript
674
+ import Editor from "@arcgis/core/widgets/Editor.js";
675
+
676
+ const editor = new Editor({
677
+ view: view,
678
+ layerInfos: [{
679
+ layer: featureLayer,
680
+ formTemplate: formTemplate,
681
+ enabled: true,
682
+ addEnabled: true,
683
+ updateEnabled: true,
684
+ deleteEnabled: true
685
+ }]
686
+ });
687
+
688
+ view.ui.add(editor, "top-right");
689
+ ```
690
+
691
+ ## Common Patterns
692
+
693
+ ### Complete Form Setup
694
+
695
+ ```javascript
696
+ const formTemplate = new FormTemplate({
697
+ title: "Property Information",
698
+ description: "Enter property details",
699
+ preserveFieldValuesWhenHidden: true,
700
+ expressionInfos: [
701
+ {
702
+ name: "is-commercial",
703
+ expression: "$feature.type == 'commercial'"
704
+ }
705
+ ],
706
+ elements: [
707
+ // Header text
708
+ {
709
+ type: "text",
710
+ text: "<b>Basic Information</b>"
711
+ },
712
+ // Required field
713
+ {
714
+ type: "field",
715
+ fieldName: "name",
716
+ label: "Property Name",
717
+ requiredExpression: "true",
718
+ input: { type: "text-box", maxLength: 100 }
719
+ },
720
+ // Dropdown
721
+ {
722
+ type: "field",
723
+ fieldName: "type",
724
+ label: "Property Type",
725
+ input: { type: "combo-box" }
726
+ },
727
+ // Conditional group
728
+ {
729
+ type: "group",
730
+ label: "Commercial Details",
731
+ visibilityExpression: "is-commercial",
732
+ elements: [
733
+ { type: "field", fieldName: "business_type", label: "Business Type" },
734
+ { type: "field", fieldName: "sqft", label: "Square Footage" }
735
+ ]
736
+ },
737
+ // Date field
738
+ {
739
+ type: "field",
740
+ fieldName: "inspection_date",
741
+ label: "Last Inspection",
742
+ input: { type: "date-picker" }
743
+ },
744
+ // Long text
745
+ {
746
+ type: "field",
747
+ fieldName: "notes",
748
+ label: "Notes",
749
+ input: { type: "text-area", maxLength: 500 }
750
+ }
751
+ ]
752
+ });
753
+ ```
754
+
755
+ ### FeatureTable with Editing
756
+
757
+ ```javascript
758
+ const featureTable = new FeatureTable({
759
+ view: view,
760
+ layer: featureLayer,
761
+ container: "tableDiv",
762
+ editingEnabled: true,
763
+ fieldConfigs: [
764
+ { name: "name", label: "Name", editable: true },
765
+ { name: "status", label: "Status", editable: true },
766
+ { name: "created_date", label: "Created", editable: false }
767
+ ]
768
+ });
769
+
770
+ featureTable.on("edit-complete", async (event) => {
771
+ console.log("Edit saved:", event.feature.attributes);
772
+
773
+ // Refresh related data
774
+ await featureLayer.refresh();
775
+ });
776
+ ```
777
+
778
+ ### Responsive Table Layout
779
+
780
+ ```javascript
781
+ const featureTable = new FeatureTable({
782
+ view: view,
783
+ layer: featureLayer,
784
+ container: "tableDiv",
785
+ autoRefreshEnabled: true,
786
+ pageSize: 25
787
+ });
788
+
789
+ // Resize handling
790
+ window.addEventListener("resize", () => {
791
+ featureTable.refresh();
792
+ });
793
+
794
+ // Toggle visibility
795
+ function toggleTable(visible) {
796
+ document.getElementById("tableDiv").style.display = visible ? "block" : "none";
797
+ if (visible) {
798
+ featureTable.refresh();
799
+ }
800
+ }
801
+ ```
802
+
803
+ ## TypeScript Usage
804
+
805
+ Form elements use autocasting with `type` properties. For TypeScript safety, use `as const`:
806
+
807
+ ```typescript
808
+ // Use 'as const' for type safety in form templates
809
+ const formTemplate = {
810
+ title: "Edit Feature",
811
+ elements: [
812
+ {
813
+ type: "field",
814
+ fieldName: "name",
815
+ label: "Name"
816
+ },
817
+ {
818
+ type: "group",
819
+ label: "Address",
820
+ elements: [
821
+ { type: "field", fieldName: "street" },
822
+ { type: "field", fieldName: "city" }
823
+ ]
824
+ }
825
+ ]
826
+ } as const;
827
+
828
+ // For input types
829
+ const formElement = {
830
+ type: "field",
831
+ fieldName: "status",
832
+ input: { type: "combo-box" }
833
+ } as const;
834
+ ```
835
+
836
+ > **Tip:** See [arcgis-core-maps skill](../arcgis-core-maps/SKILL.md) for detailed guidance on autocasting vs explicit classes.
837
+
838
+ ## Common Pitfalls
839
+
840
+ 1. **Field Names Must Match**: fieldName must exactly match layer field
841
+ ```javascript
842
+ // Layer has field "PropertyName"
843
+ { fieldName: "PropertyName" } // Correct
844
+ { fieldName: "propertyname" } // Wrong - case sensitive
845
+ ```
846
+
847
+ 2. **Coded Value Domains**: ComboBox auto-populates from domain
848
+ ```javascript
849
+ // If field has coded value domain, values come from domain
850
+ { type: "field", fieldName: "status", input: { type: "combo-box" } }
851
+ // Dropdown shows domain values automatically
852
+ ```
853
+
854
+ 3. **Expression Names**: Reference expressions by name string
855
+ ```javascript
856
+ expressionInfos: [{ name: "my-expr", expression: "..." }],
857
+ elements: [{
858
+ visibilityExpression: "my-expr" // String reference
859
+ }]
860
+ ```
861
+
862
+ 4. **Layer Must Be Editable**: For edit features to work
863
+ ```javascript
864
+ // Layer capabilities must include editing
865
+ if (layer.capabilities.editing.supportsUpdateByOthers) {
866
+ featureTable.editingEnabled = true;
867
+ }
868
+ ```
869
+
870
+ 5. **Container Size**: Table needs explicit height
871
+ ```css
872
+ #tableDiv {
873
+ height: 400px; /* Required */
874
+ width: 100%;
875
+ }
876
+ ```
877
+