Contingent values are a data design feature that allow you to make the values in one field dependent upon the values in another field. In other words, contingent values are how you define a set of attribute
What contingent values look like
You can author contingent values using ArcGIS Pro
Contingent values are defined in one or more field groups. A field group is a named collection of attribute
For each field group, contingent values define all combinations of appropriate values for the participating fields. The value you provide for each field depends on the type of domain associated with it (coded value or range). You can also provide special values to indicate that any value in the domain is considered valid or that a null value is valid (for fields that accept null values). Note that the any value also includes null.
The following image shows a field group defining a set of contingent values for power poles. The fields Voltage, Material, and Height use coded value domains for their values, while Diameter uses a range domain. Poles that have a value of Wood in the Material field can have any value for Height that's in the associated domain (or null) without violating the contingent value constraints.
Access contingent values in your app
Classes and helper methods are provided for reading contingent value definitions for a dataset and for determining contingent value violations for a specific feature
Contingent values can be read from an ArcGISFeatureTable. Here are some of the classes used to represent contingent values:
ContingentValuesDefinition—Contains all the field groups that define contingent values for the dataset. The contingent values definition is exposed as a property onArcGISFeatureTable.
-
FieldGroup—Defines all possible contingent values for a set of fields. The contingent values definition contains a collection of field groups. -
Contingency—Defines a set of contingent values for a field group. -
ContingentValue—A base class that defines a possible value for a field participating in a field group. A contingent value can be one of the following:ContingentCodedValue—A value from a coded value domain.ContingentRangeValue—Defines a minimum and maximum range of values.ContingentAnyValue—Indicates that any value in the field's domain is considered valid (as well asnull).ContingentNullValue—Indicates that anullvalue is valid for the field.
In addition to these classes, the API provides the following helper methods on ArcGISFeatureTable. In many cases, these helper methods are all you need to provide contingent value support when editing the table
-
ArcGISFeatureTable.getContingentValuesOrNull()—Returns contingent values for a provided featureA feature is a single record, also known as a row, that represents a real-world entity. It typically contains a geometry (point, multipoint, polyline, or polygon) and attributes but it can also contain just attributes. and attributeAttributes are fields and values for a single feature or non-spatial record. They are typically stored in a database or service such as a feature service. field. -
ArcGISFeatureTable.validateContingencyConstraints()—Validates a featureA feature is a single record, also known as a row, that represents a real-world entity. It typically contains a geometry (point, multipoint, polyline, or polygon) and attributes but it can also contain just attributes. against contingent values defined for the dataset.
Edit with contingent values
Contingent values do not enforce data integrity or attribute
Get contingent values
Contingent values are derived from values in an attribute
To get the contingent values for a field, use the ArcGISFeatureTable.getContingentValuesOrNull()helper method and pass the current feature
The following code gets all contingent coded values for the specified field based on the other attribute
polesFeatureTable.contingentValuesDefinition.load().onFailure { error ->
return@launch logErr("Could not load contingentValuesDefinition: ${error.message}")
}
// Store a hash map of values from the contingent values definition.
val availableValues = mutableMapOf<String, Any>()
// Get all contingent values defined for a specified field name.
// The other attribute values of the feature determine which contingent values are returned.
// Assume that feature has these attribute values:
// Voltage="High" (3); Material="Steel" (4)"; Height="65" (4); and Diameter=12.
// If the field name is "Material", the resulting contingent values are:
// Steel, Wood.
var fieldName = "Material"
var contingentValuesResult = polesFeatureTable.getContingentValuesOrNull(feature, fieldName)
?: return@launch logErr("Did not retrieve contingent values.")
// Get a list of contingent values for each field group.
var contingentVals: Map<String, List<ContingentValue>> = contingentValuesResult.byFieldGroup
var fieldGroupName = "pole_contingent_values"
// Get the contingent values for a specified field group.
var fieldGroupContingentVals = contingentVals[fieldGroupName]
?: return@launch logErr("No contingent values for the field group name.")
// Loop through all contingent values.
fieldGroupContingentVals.forEach { cv ->
// Add coded values to the hash map (name and code).
if (cv is ContingentCodedValue) {
availableValues[cv.codedValue.name] = cv.codedValue.code
?: return@launch logErr("Coded value ${cv.codedValue.name} has a null value for code.")
}
}
logInfo("availableValues: $availableValues")
If the contingent values are from a range domain, you can return the minimum and maximum values for the valid range.
// (continued from above)
availableValues.clear()
fieldName = "Diameter"
contingentValuesResult = polesFeatureTable.getContingentValuesOrNull(feature, fieldName)
?: return@launch logErr("Did not retrieve contingent values.")
// Get a list of contingent values for each field group.
contingentVals = contingentValuesResult.byFieldGroup
fieldGroupName = "pole_contingent_values"
// Get the contingent values for a specified field group.
fieldGroupContingentVals = contingentVals[fieldGroupName]
?: return@launch logErr("No contingent values for the field group name.")
// A ContingentRangeValue has a minimum and maximum value.
// Loop through all contingent values.
fieldGroupContingentVals.forEachIndexed { index, cv ->
// Add coded values to the hash map (name and code).
if (cv is ContingentRangeValue) {
availableValues["min$index"] = cv.minValue
availableValues["max$index"] = cv.maxValue
}
}
logInfo("availableValues: $availableValues")
If a ContingentAnyValue is defined for the field, you can provide all values from the field's domain as valid edit choices.
// (continued from above)
// ContingentAnyValue means all domain values for the field are valid.
availableValues.clear()
fieldGroupContingentVals.forEach { cv ->
if (cv is ContingentAnyValue) {
// Get the domain for this field and add all values to the hash map.
val domain = polesFeatureTable.getField(fieldName)?.domain as CodedValueDomain
domain.codedValues.forEach { codedValue ->
availableValues[codedValue.name] = codedValue.code as Any
}
}
}
logInfo("availableValues: $availableValues")
Validate edits against contingent values
To see if a feature's attributeArcGISFeatureTable.validateContingencyConstraints() helper method and pass a featureContingencyConstraintViolation that you can use to enforce edit restrictions or provide warnings to the user.
Each contingency constraint violation indicates if it is a warning or an error, and which field group contains the violated contingent value. A violation is considered an error if the field group is marked as restrictive, meaning that edits to any participating fields must conform to previously defined contingent values. If a field group is not marked restrictive, the violation is considered a warning.
// Get any contingency constraint violations for the new feature.
val contingentValueViolations = polesFeatureTable.validateContingencyConstraints(feature)
// If there are no violations, let the user save.
if (contingentValueViolations.isEmpty()) {
// Enable the Save feature button in your app:
// saveFeatureButton.isEnabled = true
return@launch logInfo("Contingent values validated")
}
// Loop through contingency violations and show messages for errors and warnings.
// Include the name of the field group that had the violation.
var msg = "Contingency value violation for field group(s): "
contingentValueViolations.forEach { contValViolation ->
msg = msg + "'" + contValViolation.fieldGroup.name + "' "
}
// Show the field groups that had violations.
logInfo(msg)
