Select to view content in your preferred language

Using popupElement for Arcade Content

156
0
2 weeks ago
Brian_McLeer
Occasional Contributor III

I am trying to batch-update multiple layers to all have the same Arcade content applied. I have found documentation on using a combination of Attribute Expressions / Text elements, but for the particular Arcade I am using, it only functions correctly if Arcade content is applied. 

Brian_McLeer_0-1723837753133.png

I have looked through the developer documentation and it does not appear to call out Arcade as a popupElement supported function. 

Here is my current code, but ultimately I would like to remove the Attribute Expression and Text element and use Arcade as this works for hyperlinking out to URLs. 

 

from arcgis.gis import GIS
from arcgis.mapping import WebMap

# Step 1: Connect to the Portal
gis = GIS("https://portal.website.com/portal/", "username", "password")

# Step 2: Access the Web Map
webmap_item = gis.content.get("itemid")
webmap = WebMap(webmap_item)

# Function to clean popupInfo, remove attribute expressions, text boxes, and fields list
def clean_popup(layer):
    # Update the layer title to remove ":" and references to "fields"
    if "title" in layer:
        original_title = layer["title"]
        new_title = original_title.replace(':', '').replace('fields', '', 1).strip()
        layer["title"] = new_title
        if original_title != new_title:
            print(f"Updated layer title from '{original_title}' to '{new_title}'")

    # Clean the popupInfo to remove attribute expressions, fields list, and text boxes
    if "popupInfo" in layer:
        popup_info = layer["popupInfo"]

        # Clear popupElements to remove Fields list, text elements, and any other custom elements
        popup_info["popupElements"] = []

        # Remove fieldInfos and attribute expressions (expressionInfos) completely
        popup_info.pop("fieldInfos", None)
        popup_info.pop("expressionInfos", None)  # Removes any existing attribute expressions

        # Remove other potential field-related properties
        field_related_keys = ['displayField', 'description', 'showAttachments', 'mediaInfos']
        for key in field_related_keys:
            popup_info.pop(key, None)

        print(f"Cleaned popupInfo for layer: {layer.get('title', 'Unnamed Layer')}")

# Function to add an Arcade attribute expression and reference it in a text element
def add_arcade_expression_as_text(layer):
    if "popupInfo" in layer:
        popup_info = layer["popupInfo"]

        # Define the Arcade attribute expression
        arcade_expression = {
            "name": "customContent",
            "title": "Custom Content",
            "expression": """
                var fieldsToExclude = ["OBJECTID", "OBJECTID_1", "SHAPE", "LAYERNAME", "GLOBALID", "SHAPE.STAREA()", "SHAPE.STLENGTH()", "CREATED_USER", "CREATED_DATE", "LAST_EDITED_USER", "LAST_EDITED_DATE", "LASTMODBY", "LASTMODDATE", "LASTSYNDATE"];
                var content = "";
                var seenUrls = {};

                function formatURL(label, value) {
                    return label + ": <a target='_blank' href='" + value + "'>Click here for more info.</a>";
                }

                Expects($feature, "*");

                var schemaDict = Schema($feature);
                var fieldsArray = schemaDict["fields"];

                function getFieldAlias(fieldName) {
                    for (var j = 0; j < Count(fieldsArray); j++) {
                        var fieldDict = fieldsArray[j];
                        if (fieldDict['name'] == fieldName) {
                            return fieldDict['alias'];
                        }
                    }
                    return fieldName;
                }

                function formatDate(dateValue) {
                    var date = Date(dateValue);
                    return Text(date, "MM/DD/YYYY");
                }

                function getDomainDescription(fieldDict, value) {
                    if (HasKey(fieldDict, "domain")) {
                        var domain = fieldDict["domain"];
                        if (domain != null && HasKey(domain, "codedValues")) {
                            for (var k = 0; k < Count(domain["codedValues"]); k++) {
                                var codedValue = domain["codedValues"][k];
                                if (codedValue["code"] == value) {
                                    return codedValue["name"];
                                }
                            }
                        }
                    }
                    return value;
                }

                for (var i = 0; i < Count(fieldsArray); i++) {
                    var fieldDict = fieldsArray[i];
                    var fieldName = fieldDict["name"];
                    var alias = fieldDict["alias"];
                    var value = $feature[fieldName];

                    if (IndexOf(fieldsToExclude, Upper(fieldName)) == -1 && !IsEmpty(value) && Upper(Text(value)) != "NULL") {
                        if (Upper(Left(Text(value), 7)) == "HTTP://" || Upper(Left(Text(value), 8)) == "HTTPS://") {
                            if (!HasKey(seenUrls, value)) {
                                content += formatURL(alias, value) + "\\n";
                                seenUrls[value] = true;
                            }
                        } else if (fieldDict.type == "esriFieldTypeDate") {
                            content += alias + ": " + formatDate(value) + "\\n";
                        } else if (HasKey(fieldDict, "domain") && fieldDict["domain"] != null) {
                            var domainDescription = getDomainDescription(fieldDict, value);
                            content += alias + ": " + Text(domainDescription) + "\\n";
                        } else {
                            content += alias + ": " + Text(value) + "\\n";
                        }
                    }
                }

                return content;
            """
        }

        # Add the Arcade expression to the expressionInfos
        if "expressionInfos" not in popup_info:
            popup_info["expressionInfos"] = []
        popup_info["expressionInfos"].append(arcade_expression)

        # Reference the Arcade expression in a text element
        text_element = {
            "type": "text",
            "text": "{expression/customContent}"
        }

        # Add the text element to the popupElements
        popup_info["popupElements"].append(text_element)
        print(f"Added Arcade expression as a text element to layer: {layer.get('title', 'Unnamed Layer')}")

# Recursive function to process all layers, including nested layers
def process_layers(layers):
    for layer in layers:
        clean_popup(layer)
        add_arcade_expression_as_text(layer)

        # Process sublayers if the layer is a group
        if "layers" in layer:
            print(f"Processing sublayers of group layer: {layer.get('title', 'Unnamed Layer')}")
            process_layers(layer["layers"])

# Step 3: Process all layers, including those within group layers
process_layers(webmap.layers)

# Step 4: Save the updated Web Map
webmap.update()

print("All attribute expressions, fields lists, and text boxes removed, titles updated, and Arcade content added as a text element.")

 

 

When I apply the below in an Arcade content section, the hyperlinks work. Whereas if I do it in an Attribute Expression and Text content, everything but the hyperlink works. 

 

var fieldsToExclude = ["OBJECTID", "SHAPE", "LAYERNAME", "GLOBALID", "SHAPE.STAREA()", "SHAPE.STLENGTH()", "CREATED_USER", "CREATED_DATE", "LAST_EDITED_USER", "LAST_EDITED_DATE", "LASTMODBY", "LASTMODDATE", "LASTSYNDATE"];
var content = "";
var seenUrls = {};

// Function to format URL fields
function formatURL(label, value) {
    return "<b>" + label + ":</b> <a target='_blank' href='" + value + "'>Click here for more info.</a><br/>";
}

// Ensure all fields are available
Expects($feature, "*");

// Get the schema of the feature's layer
var schemaDict = Schema($feature);
var fieldsArray = schemaDict["fields"];

// Function to get the alias of a field
function getFieldAlias(fieldName) {
    for (var j = 0; j < Count(fieldsArray); j++) {
        var fieldDict = fieldsArray[j];
        if (fieldDict['name'] == fieldName) {
            return fieldDict['alias'];
        }
    }
    return fieldName; // Fallback to field name if alias is not found
}

// Function to format dates as mm/dd/yyyy
function formatDate(dateValue) {
    var date = Date(dateValue);
    return Text(date, "MM/DD/YYYY");
}

// Function to get domain description
function getDomainDescription(fieldDict, value) {
    // First, ensure that the domain key exists and is not null
    if (HasKey(fieldDict, "domain")) {
        var domain = fieldDict["domain"];
        if (domain != null && HasKey(domain, "codedValues")) {
            for (var k = 0; k < Count(domain["codedValues"]); k++) {
                var codedValue = domain["codedValues"][k];
                if (codedValue["code"] == value) {
                    return codedValue["name"];
                }
            }
        }
    }
    return value; // Fallback to original value if no domain or match is found
}

// Iterate over each field in the schema to respect the field order
for (var i = 0; i < Count(fieldsArray); i++) {
    var fieldDict = fieldsArray[i];
    var fieldName = fieldDict["name"];
    var alias = fieldDict["alias"];
    var value = $feature[fieldName];

    // Exclude certain fields and check if value is not empty
    if (IndexOf(fieldsToExclude, Upper(fieldName)) == -1 && !IsEmpty(value) && Upper(Text(value)) != "NULL") {
        // Check if the field value is a URL and format accordingly
        if (Upper(Left(Text(value), 7)) == "HTTP://" || Upper(Left(Text(value), 8)) == "HTTPS://") {
            if (!HasKey(seenUrls, value)) {
                content += formatURL(alias, value);
                seenUrls[value] = true;
            }
        } else if (fieldDict.type == "esriFieldTypeDate") {
            // Format date fields
            content += "<b>" + alias + ":</b> " + formatDate(value) + "<br/>";
        } else if (HasKey(fieldDict, "domain") && fieldDict["domain"] != null) {
            // Use domain description if available
            var domainDescription = getDomainDescription(fieldDict, value);
            content += "<b>" + alias + ":</b> " + Text(domainDescription) + "<br/>";
        } else {
            content += "<b>" + alias + ":</b> " + Text(value) + "<br/>";
        }
    }
}

return {
    type: 'text',
    text: content // this property supports HTML tags
};

 

 

 

 

 

Brian
0 Kudos
0 Replies