<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Using popupElement for Arcade Content in ArcGIS API for Python Questions</title>
    <link>https://community.esri.com/t5/arcgis-api-for-python-questions/using-popupelement-for-arcade-content/m-p/1581765#M11131</link>
    <description>&lt;P&gt;&lt;a href="https://community.esri.com/t5/user/viewprofilepage/user-id/417766"&gt;@Clubdebambos&lt;/a&gt;&amp;nbsp;thank you for the feedback, I will review this over the next few weeks and let you know if I have any luck. After I made this post, I made a support case and Esri noted that it is not a functionality yet in the Python API for Arcade elements but may be in the future.&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Tue, 04 Feb 2025 15:21:37 GMT</pubDate>
    <dc:creator>Brian_McLeer</dc:creator>
    <dc:date>2025-02-04T15:21:37Z</dc:date>
    <item>
      <title>Using popupElement for Arcade Content</title>
      <link>https://community.esri.com/t5/arcgis-api-for-python-questions/using-popupelement-for-arcade-content/m-p/1523094#M11085</link>
      <description>&lt;P&gt;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.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Brian_McLeer_0-1723837753133.png" style="width: 400px;"&gt;&lt;img src="https://community.esri.com/t5/image/serverpage/image-id/112666i6DEC926BC31BCFF0/image-size/medium?v=v2&amp;amp;px=400" role="button" title="Brian_McLeer_0-1723837753133.png" alt="Brian_McLeer_0-1723837753133.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;I have looked through the &lt;A href="https://developers.arcgis.com/web-map-specification/objects/popupElement/" target="_self"&gt;developer documentation&lt;/A&gt; and it does not appear to call out Arcade as a popupElement supported function.&amp;nbsp;&lt;/P&gt;&lt;P&gt;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.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;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 + ": &amp;lt;a target='_blank' href='" + value + "'&amp;gt;Click here for more info.&amp;lt;/a&amp;gt;";
                }

                Expects($feature, "*");

                var schemaDict = Schema($feature);
                var fieldsArray = schemaDict["fields"];

                function getFieldAlias(fieldName) {
                    for (var j = 0; j &amp;lt; 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 &amp;amp;&amp;amp; HasKey(domain, "codedValues")) {
                            for (var k = 0; k &amp;lt; Count(domain["codedValues"]); k++) {
                                var codedValue = domain["codedValues"][k];
                                if (codedValue["code"] == value) {
                                    return codedValue["name"];
                                }
                            }
                        }
                    }
                    return value;
                }

                for (var i = 0; i &amp;lt; 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 &amp;amp;&amp;amp; !IsEmpty(value) &amp;amp;&amp;amp; 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") &amp;amp;&amp;amp; 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.")&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;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.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="java"&gt;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 "&amp;lt;b&amp;gt;" + label + ":&amp;lt;/b&amp;gt; &amp;lt;a target='_blank' href='" + value + "'&amp;gt;Click here for more info.&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;";
}

// 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 &amp;lt; 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 &amp;amp;&amp;amp; HasKey(domain, "codedValues")) {
            for (var k = 0; k &amp;lt; 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 &amp;lt; 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 &amp;amp;&amp;amp; !IsEmpty(value) &amp;amp;&amp;amp; 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 += "&amp;lt;b&amp;gt;" + alias + ":&amp;lt;/b&amp;gt; " + formatDate(value) + "&amp;lt;br/&amp;gt;";
        } else if (HasKey(fieldDict, "domain") &amp;amp;&amp;amp; fieldDict["domain"] != null) {
            // Use domain description if available
            var domainDescription = getDomainDescription(fieldDict, value);
            content += "&amp;lt;b&amp;gt;" + alias + ":&amp;lt;/b&amp;gt; " + Text(domainDescription) + "&amp;lt;br/&amp;gt;";
        } else {
            content += "&amp;lt;b&amp;gt;" + alias + ":&amp;lt;/b&amp;gt; " + Text(value) + "&amp;lt;br/&amp;gt;";
        }
    }
}

return {
    type: 'text',
    text: content // this property supports HTML tags
};&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 16 Aug 2024 19:59:44 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-api-for-python-questions/using-popupelement-for-arcade-content/m-p/1523094#M11085</guid>
      <dc:creator>Brian_McLeer</dc:creator>
      <dc:date>2024-08-16T19:59:44Z</dc:date>
    </item>
    <item>
      <title>Re: Using popupElement for Arcade Content</title>
      <link>https://community.esri.com/t5/arcgis-api-for-python-questions/using-popupelement-for-arcade-content/m-p/1578584#M11086</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://community.esri.com/t5/user/viewprofilepage/user-id/346604"&gt;@Brian_McLeer&lt;/a&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Seems like you were very close. The expressions element is the Arcade element that you see in the &lt;A href="https://developers.arcgis.com/web-map-specification/objects/popupElement_expression/" target="_blank" rel="noopener"&gt;documentation&lt;/A&gt;.&amp;nbsp;&lt;/P&gt;&lt;P&gt;My go to is to do it manually in a WebMap and then grab the JSON from the definition for that layer. In your instance you only want an &lt;EM&gt;expression&lt;/EM&gt; element in your&lt;EM&gt; popupElements&lt;/EM&gt; that reflects your Arcade.&lt;/P&gt;&lt;LI-CODE lang="python"&gt;## API version 2.4.0 (will work for previos versions too)

from arcgis.gis import GIS
import json

## Access ArcGIS Online
agol = GIS("home")

## get the WebMap Item object
wm_item = agol.content.get("WM_ITEM_ID")

## get teh WebMap definition
wm_item_data = wm_item.get_data()

## get teh definition for the layer of interest
## example below: the first layer [0]
lyr = wm_item_data["operationalLayers"][0]

## print the definition for that layer to screen.
## you are interested in the "popupInfo"
print(json.dumps(lyr, indent=4))&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Example:&lt;/P&gt;&lt;LI-CODE lang="python"&gt;"popupInfo": {
        "popupElements": [
            {
                "type": "expression",
                "expressionInfo": {
                    "title": "My Arcade Expression",
                    "expression": "var display = Concatenate($feature.Name, \" \", $feature.Score);\n\nreturn { \n\ttype : 'text', \n\ttext : display\n}",
                    "returnType": "dictionary"
                }
            }
        ],
        "fieldInfos": [
            {
                "fieldName": "OBJECTID",
                "isEditable": false,
                "label": "OBJECTID",
                "visible": false
            },
            {
                "fieldName": "Name",
                "isEditable": true,
                "label": "Name",
                "visible": true
            },
            {
                "fieldName": "ORIG_FID",
                "format": {
                    "digitSeparator": true,
                    "places": 0
                },
                "isEditable": true,
                "label": "ORIG_FID",
                "visible": true
            },
            {
                "fieldName": "Score",
                "isEditable": true,
                "label": "Score",
                "visible": true
            }
        ],
        "title": "TEST_LAYER: {Name}"
    }&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I'm really only interested in the popupElements as I only want an Arcade expression controlling the Popup.&lt;/P&gt;&lt;LI-CODE lang="python"&gt;from arcgis.gis import GIS

## Access ArcGIS Online
agol = GIS("home")

## the popupElements to use in Popups
## One element below, the Arcade Expression
popupElements = [
    {
        "type": "expression",
        "expressionInfo": {
            "title": "My Arcade Expression",
            "expression": "var display = Concatenate($feature.Name, \" \", $feature.Score);\n\nreturn { \n\ttype : 'text', \n\ttext : display\n}",
            "returnType": "dictionary"
        }
    }
]

## get the WebMap Item object
wm_item = agol.content.get("WM_ITEM_ID")

## get the WebMap definition
wm_item_data = wm_item.get_data()

## apply the popupElements to the specific layer.
wm_item_data["operationalLayers"][0]["popupInfo"]["popupElements"] = popupElements

## update the WebMap item objecy
update_definition = {"text" : wm_item_data}

wm_item.update(update_definition)&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I hope that helps,&lt;/P&gt;&lt;P&gt;Glen&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 24 Jan 2025 11:09:29 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-api-for-python-questions/using-popupelement-for-arcade-content/m-p/1578584#M11086</guid>
      <dc:creator>Clubdebambos</dc:creator>
      <dc:date>2025-01-24T11:09:29Z</dc:date>
    </item>
    <item>
      <title>Re: Using popupElement for Arcade Content</title>
      <link>https://community.esri.com/t5/arcgis-api-for-python-questions/using-popupelement-for-arcade-content/m-p/1581765#M11131</link>
      <description>&lt;P&gt;&lt;a href="https://community.esri.com/t5/user/viewprofilepage/user-id/417766"&gt;@Clubdebambos&lt;/a&gt;&amp;nbsp;thank you for the feedback, I will review this over the next few weeks and let you know if I have any luck. After I made this post, I made a support case and Esri noted that it is not a functionality yet in the Python API for Arcade elements but may be in the future.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 04 Feb 2025 15:21:37 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-api-for-python-questions/using-popupelement-for-arcade-content/m-p/1581765#M11131</guid>
      <dc:creator>Brian_McLeer</dc:creator>
      <dc:date>2025-02-04T15:21:37Z</dc:date>
    </item>
  </channel>
</rss>

