ArcGIS Online

From the Smart Editor to Smart Forms

This blog focuses on replicating the Smart Editor widget functionality using Smart Forms. For new examples, see Go Beyond the Smart Editor using Smart Forms.

As you migrate from Web AppBuilder to leverage Experience Builder, you’ll be moving from the Smart Editor widget to the Editor widget.

Use the Editor widget with Smart Forms to improve your editing experiences and automatically calculate attributes. This widget is available in Map Viewer and app builders such as Experience Builder and Instant Apps.

To build Forms in Map Viewer, all you need is an editable layer. If this is your first time, read this blog to get started.

Configure form in Map Viewer
Configure a Smart Form in the Map Viewer and add Calculated expressions

To replicate the Smart Editor widget functionality, use Calculated expressions and the Arcade scripting language.

Now, if you’re like me, you may turn pale at the thought of having to write lines of code. This is why I’m providing some samples to help you get started.

 

Attribute Actions

In the Smart Editor widget, Intersection, Preset, Coordinate and Address Attribute Actions can be set to populate default values or to calculate values on the fly across different layers using location information.

The examples in this blog can also be found in this sample web map. To view them in action, open the Edit widget and create a New Feature on the map.

Sample web map with Smart Forms
In the sample web map, open the Edit widget and create a new feature to view the examples in action

Intersection

In the Smart Editor widget, Intersection Attribute Actions allow you to populate an attribute field based on a field value sourced from intersecting layers in the map.

Use the Intersects geometry function from the Arcade library to recreate this functionality using calculated expression in the Smart Forms.

Fetch an attribute value from an intersecting feature

Example: Copy the Zip code attribute value from the USA ZIP Code Boundaries layer into the corresponding field of the layer being edited.

Fetch an attribute value from an intersecting feature
Calculation of a value from an intersecting feature using the Smart Editor widget (Web AppBuilder) [left] and a calculated expression in the Smart Forms (Map Viewer) [right]. In this example, the Zip Code is copied from a the USA ZIP Code Boundaries layer into the ZIP Code field of the point layer being edited

In the Smart Editor widget, you can select the source layer and field to extract a value and define the target fields to apply the extracted value.

Intersection Attribute Action in the Smart Editor widget
Configure an Intersection Attribute Action in the Smart Editor widget

With Smart Forms, write an expression to define the source layer, the intersection function, and the target layer. See the sample web map.

Click here to show the sample code

Copy the code below to create your own calculations:

// Step 1. Define the source layer and fields to intersect./
// To customize below, replace the layer and field names.
var source_layer = FeatureSetByName($map,"USA ZIP Code Boundaries", ['ZIP_CODE'])

// Step 2. Intersect the current location with the source layer and get the field value. 
// If there are multiple intersecting features, get the value from the feature that is 
// first returned by the query.
var get_value = First(Intersects($feature, source_layer))

// Step 3. If the current location intersects the source layer, return the value from the source field. 
Otherwise return null.
// To customize below replace the field name.
if (!IsEmpty(get_value)) {
    return get_value['ZIP_CODE']
} else {
    return null
}

         

 

Fetch an attribute value from a nearby feature (closest)

Example: Find the closest Bus Stop point feature (within a 1,000 feet buffer).

Fetch an attribute value from a nearby feature (closest)
Find the closest bus stop point feature, which can also be found within a 1,000 feet tolerance buffer area, and get the stop's name attribute value

Write a Calculated expression to define the source layer, buffer the current location, and use the intersection function to find the closest feature. See the sample web map.

Click here to show the sample code

Copy the code below to create your own calculations:

// If the feature doesn't have a geometry, return null
if (IsEmpty(Geometry($feature))) { return null }
// Get the bus stops layer
// To customize, replace the layer name below
var busStops = FeatureSetByName($map,"RTD Active Bus Stops")
// Buffer the current location and intersect with the bus stops
var bufferedLocation = Buffer($feature, 1000, 'feet')
var candidateStops = Intersects(busStops, bufferedLocation)
// Calculate the distance between the bus stops and the current location
// Store the feature and distance as a dictionary and push it into an array
var featuresWithDistances = []
for (var f in candidateStops) {
    Push(featuresWithDistances, 
        {
            'distance': Distance($feature, f, 'feet'),
            'feature': f
        }
    )
}
// Sort the candidate bus stops by distance using a custom function
function sortByDistance(a, b) {
    return a['distance'] - b['distance']
}
var sorted = Sort(featuresWithDistances, sortByDistance)
// Get the closest bus stop
var closestFeatureWithDistance = First(sorted)
// If there was no bus stop, return null
if (IsEmpty(closestFeatureWithDistance)) { return null }
// Return the bus stop name attribute value
// To customize, replace the field name "STOPNAME" below
return `${closestFeatureWithDistance['feature']['STOPNAME']}`

         

 

Fetch an attribute value from an intersecting feature based on layer priority

Example: Get an attribute value from intersecting and overlapping polygon features based on the priority defined for their parent layer.

Intersection example based on layer priority
Get an attribute value from intersecting and overlapping polygon features based on the priority defined for their parent layer

Write an expression to define the priority (or ranking) for each target layer, intersect the current location with each layer, and determine which value to prioritize. See the sample web map.

Click here to show the sample code

Copy the code below to create your own calculations:

// Step 1. Get the layers from the map
// You can use FeatureSetById or FeatureSetByName 
var layer_priority1 = FeatureSetById($map, /* Priority 1 */ "185a34dd0ee-layer-13");
var layer_priority2 = FeatureSetById($map, /* Priority 2 */ "185a34dd0ee-layer-12");
var layer_priority3 = FeatureSetById($map, /* Priority 3 */ "185a34dd0ee-layer-11"); 

// Step 2. Intersect the current location with the layers
var priority1Features = Intersects(layer_priority1, $feature);
var priority2Features = Intersects(layer_priority2, $feature);
var priority3Features = Intersects(layer_priority3, $feature); 

// Step 3. If there are multiple intersecting features per layer, 
// get the value from the feature that is first returned by the query
var a = First(priority1Features);
var b = First(priority2Features);
var c = First(priority3Features); 

// Step 4. Define the fields and order to get the values from
// intersecting features based on their layer priority.
// To customize, replace the field names "Priority1", "Priority2",
// and "Priority3" below.
When( 
  !IsEmpty(a), a.Priority1, 
  !IsEmpty(b), b.Priority2, 
  !IsEmpty(c), c.Priority3, 
  "No Intersection"
);

         

 

Preset

In the Smart Editor widget, Preset Attribute Actions allow you to prepopulate fields with attribute values when creating new features. This facilitates consistent and rapid data collection.

Preset Attribute Actions and calculation of default values
Define default values and calculate relative date and time values using the Smart Editor widget (on the left) and the Smart Forms (on the right)

Use the Date functions from the Arcade library and very simple expressions to recreate this functionality in the Smart Forms. See the sample web map for the examples below.

Hardcoded value

If no default value was defined at the schema level for a field, you can still define it using a very simple expression. For example:

// Simply specify the value to be written into 
// the attribute field using quotes.
"This is a hard coded text value."

Date values

Current Date and Time

Preset an attribute value to provide the current date and time at the moment the feature is created and updated. For example:

// Use the Now() function to dynamically get the current date and time 
Now()

Relative Date and Time

Preset an attribute value to provide a date and time relative to another date and time value, in the past or the future. For example, here’s how to define the date and time 2 days from the moment the feature is created or updated:

// Step 1. Define the start date
var startDate = Now();
// Step 2. Define how much time to add to the start date
var twoDaysLater = DateAdd(startDate, 2, 'days');
// Step 3. Return the resulting date
return twoDaysLater;

 

Coordinates

In the Smart Editor widget, Coordinate Attribute Actions allow you to populate a field based on coordinates. Coordinates can be latitude-longitude, the map’s spatial reference, or Military Grid Reference System (MGRS).

Example: Get the latitude-longitude coordinates when I create and update the geometry of a point feature.

Calculate and store latitude-longitude coordinates with the Smart Forms
When creating and updating the geometry of a point feature using the Editor widget, calculate and store its latitude-longitude coordinates in an attribute field

To achieve this with Arcade, you’ll need to write a custom function to convert meters to latitude and longitude, and use the Geometry function from the Arcade library.

Click here to show the sample code

Copy the code below to create your own calculations:

// The expression below if only applicable if the basemap is
// using the Web Mercator projection.
// Create a function to convert meters to lat, long
// Source: http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/
function MetersToLatLon(geom) {
    if (IsEmpty(geom)) {
        return [null, null]
    }
    var originShift = 2.0 * PI * 6378137.0 / 2.0    
    var lon = (geom.x / originShift) * 180.0
    var lat = (geom.y / originShift) * 180.0 
    lat = 180.0 / PI * (2.0 * Atan( Exp( lat * PI / 180.0)) - PI / 2.0)    
    return [Round(lat, 6), Round(lon, 6)]
}
// Call the function and return the latitude and longitude values
MetersToLatLon(Geometry($feature))[0] + ", " + MetersToLatLon(Geometry($feature))[1]

         

 

Address

In the Smart Editor widget, Address Attribute Actions allow you to populate a field based on an address at a specified location using a locator service.

Example: Fetch the matching address value at the location of the point feature when it’s created or its geometry is updated.

Fetch the matching address value using the Smart Editor widget
Using the Smart Editor widget, fetch the matching address value at the location of the point feature when it’s created or its geometry is updated

Reverse Geocoding is not yet available using Calculated expressions in Smart Forms.

Possible workaround: use an Intersects function to fetch the nearest feature, in the case of address points.

 

Smart Actions

In the Smart Editor widget, Smart Actions use custom expressions to define the behavior applied to an attribute field such as being required, hidden, or disabled.

Configure Smart Actions in the Smart Editor widget
Example of Smart Action configuration in the Smart Editor widget (Web AppBuilder)

When configuring a Form, you can set dynamic behavior to make fields Editable (or Read-only), Required, and Visible (or hidden).

Set dynamic behavior for fields with Arcade expressions
Set dynamic behavior for fields with Arcade expressions

Set Dynamic Behavior

To achieve this in Smart Forms, you can either build a simple condition expression using the dropdown options or write a custom one in the Arcade editor.

Example: Hide a field if it’s empty. The field in this example only takes in values from the nearest intersecting feature determined with a Calculated expression. The value will be empty if there is no intersecting feature.

The field is hidden when empty
Use the Editor widget and Smart Forms to hide a field when the value is empty if there is no intersecting feature.
Expression editor for conditional visibility
Update the expression using dropdowns or the advanced Arcade editor

Using Smart Forms in App Builders

Although Smart Forms can be created with form builders in Map Viewer or Field Maps, they are not limited to these products. Since Forms are stored in the web map, you can also use them in Experience Builder, Instant Apps, and custom apps you build using the Editor widget.

Experience Builder

Below is an app configuration example using the sample web map from this blog.

Experience Builder application
Experience Builder application configuration using the Edit widget with Smart Forms

Instant Apps

Below is an app configuration example of the Sidebar template using the sample web map from this blog.

Sidebar Instant Apps application
Sidebar Instant Apps application configuration using the Edit widget with Smart Forms

 

Get Started

Use the samples provided in this blog to build Smart Forms and improve your editing experiences.

To learn how to configure Forms and add Calculated expressions, read this blog and refer to the documentation.

Looking for more expression examples? Check out Go Beyond the Smart Editor using Smart Forms, and this growing arcade-expression GitHub repository.

About the author

Alix works on the ArcGIS Solutions Web Development team as a Product Engineer to successfully deliver industry web tools for ArcGIS Web AppBuilder, ArcGIS Experience Builder, and ArcGIS Maps SDK for JavaScript since 2019. Prior to her work at Esri, she assisted in the digital GIS transformation of a property and land management organization in New Zealand and coauthored Esri Learn lessons for Public Safety. She has a degree in GIS from Université de Sherbrooke (Québec, Canada).

Connect:
8 Comments
Oldest
Newest
Inline Feedbacks
View all comments

Next Article

ArcGIS Utility Network at the 2023 User Conference

Read this article