Select to view content in your preferred language

Help understanding Arcade expression to create table

1922
7
Jump to solution
08-03-2023 05:58 AM
Labels (3)
ZachBodenner
MVP Regular Contributor

Hello,

I'm not super proficient with Arcade but I'm trying to get better! Specifically, loops and iterations aren't super clear to me at all. Recently I was going through a blog post from ESRI about improving popups with arcade (this one specifically deals with cluster popups). The entire popup syntax is below:

Expects($aggregatedFeatures, "is_night", "type");

var crimes = $aggregatedFeatures;

// Queries the count of crimes grouped by the "type" field
var stats = GroupBy(crimes, ["type"],
  [
    { name: "total", expression: "1", statistic: "count" },
    { name: "nightPercent", expression: "is_night", statistic: "avg" }
  ]
);

// Orders the results in descending order by the total count
var topCrimes = Top(OrderBy(stats, "total desc"), 5);

if(Count(topCrimes) == 0){
  return {
    type: "text",
    text: "No crimes committed in this area"
  };
}

// Build an HTML table to display the summary of
// crimes by count and how many occurred at night
var cssGray = "style='background-color:#d6d6d6;'";
var cssRight = "style='text-align: right;'";
var cssCenter = "style='text-align: center;'";

var table = "<table style='width: 100%'>";
table += `<tr>
  <td ${cssCenter}><b>Category</b></td>
  <td ${cssCenter}><b>Count</b></td>
  <td ${cssCenter}><b>% at night</b></td>
</tr>`;

var i = 0;
for(var item in topCrimes){
  var num_crimes = Text(item.total, "#,###");
  var night_percent = Text(item.nightPercent, "#%");
  var crimeType = item["type"];

  table += `<tr ${IIF( i % 2 != 0, cssGray, null )}>
    <td>${crimeType}</td>
    <td ${cssRight}>${num_crimes}</td>
    <td ${cssRight}>${night_percent}</td>
  </tr>`;
  i++;
}
table += "</table>";

// Return the table as a text element
return {
  type: "text",
  text: table
};
 
In particular I am interested in this section:
 
table += `<tr ${IIF( i % 2 != 0, cssGray, null )}>
    <td>${crimeType}</td>
    <td ${cssRight}>${num_crimes}</td>
    <td ${cssRight}>${night_percent}</td>
  </tr>`;
  i++;
}
table += "</table>";
 
What this seems to do in the popup is configure a table to have alternating background colors for the table rows (as well as right-aligning the return text). Can someone please explain to me how this works? Does the function index rows and somehow determine if it's an even row vs. odd row? 
 
I have some tables constructed in HTML popups that are a pain to adjust because I hard-code the background color manually into alternating table rows. This really looks like it could make my life easier if I could figure it out.
 
Thanks!
1 Solution

Accepted Solutions
KenBuja
MVP Esteemed Contributor

A couple of things. Your code is looping through at the fields of the feature, but you're returning only the one attribute for Cultivar for each field. Also, you're arbitrarily setting the size of the table to 350 px, which is larger than the popup width. Use width=100%, which will make the table as big as the longest value and attribute. Try this instead (and please use the syntax button when adding code)

// Build an HTML table to display the summary of
// crimes by count and how many occurred at night
var cssGray = "style='background-color:#d6d6d6;'";
var cssRight = "style='text-align: right;'";
var cssCenter = "style='text-align: center;'";

var table = "<table style='width: 100%'>";

var i = 0;
for(var item in $feature){
 
  table += `<tr ${IIF( i % 2 != 0, cssGray, null )}>
    <td ${cssRight}>${item}</td>
    <td ${cssRight}>${$feature[item]}</td>
  </tr>`;
  i++;
}
table += "</table>";

// Return the table as a text element
return {
  type: "text",
  text: table
};

 

View solution in original post

0 Kudos
7 Replies
KenBuja
MVP Esteemed Contributor

The way it determine if it's an even or odd row is in this bit of code:

{IIF( i % 2 != 0, cssGray, null )

The % is a remainder operator, which returns the number left over when the first operator is divided by the second operator. If an even number is divided by 2, the remainder is 0. The variable i is a counter, which increments as each row is added to the table as it loops through the TopCrimes variable. In the first row, i = 0, so the remainder of i/2 is equal to 0. The first part of the IIF statement is false (0 != 0), so the color is null.

0 Kudos
ZachBodenner
MVP Regular Contributor

Thanks! I think I was pretty close to that somewhere in my brain. Okay, so then my followup question: this expression here creates some variables and does some statistical operations, more complicated than I need for my average layer popup - what if I just want to create a table from the attributes as-is? How would I construct the table that uses that alternating row function that would automatically place the attribute name and value in two columns of a table while applying alternating background colors?

0 Kudos
KenBuja
MVP Esteemed Contributor

How is what your looking for different than the existing popup field element?

0 Kudos
ZachBodenner
MVP Regular Contributor

Good question, so the table from the above expression looks like this:

ZachBodenner_0-1691073090812.png



It creates variables that count instances of a different field (crime type). I really only need to show the actual attribute values present in a layer, at least at this point. A popup that I would like to re-create using a similar expression but is right now built with HTML is:

ZachBodenner_1-1691073193645.png


So just "Attribute Name"       {Attribute Value}

Below is the HTML I current use to make that popup above. 

<table style="color: rgb(76, 76, 76); width: 250px;">

    <tbody>

        <tr>

            <td><b>Asset Type</b></td>

            <td>{AssetType}<br /></td>

        </tr>

        <tr></tr>

        <tr>

            <td style="background-color: rgb(225, 225, 225);"><b>Materials</b></td>

            <td style="background-color: rgb(225, 225, 225);">{Material}<br /></td>

        </tr>

        <tr>

            <td><b>Color</b></td>

            <td>{Color}</td>

        </tr>

        <tr>

            <td style="background-color: rgb(225, 225, 225);"><b>Feature Details</b></td>

            <td style="background-color: rgb(225, 225, 225);">{FeatureDetails}</td>

        </tr>

        <tr>

            <td><b>Condition</b></td>

            <td>{Condition}</td>

        </tr>

        <tr>

            <td style="background-color: rgb(225, 225, 225);"><b>Is Memorial Bench?</b></td>

            <td style="background-color: rgb(225, 225, 225);">{Memorial}</td>

        </tr>

        <tr>

            <td><b>Memorial Name</b></td>

            <td>{MemorialName}</td>

        </tr>

        <tr>

            <td style="background-color: rgb(225, 225, 225);"><b>Ownership</b></td>

            <td style="background-color: rgb(225, 225, 225);">{Ownership}</td>

        </tr>

        <tr>

            <td><b>Maintenance Needed</b></td>

            <td>{MaintenanceNeeded}</td>

        </tr>

        <tr>

            <td style="background-color: rgb(225, 225, 225);"><b>Maintenance Priority</b></td>

            <td style="background-color: rgb(225, 225, 225);">{MaintenancePriority}</td>

        </tr>

        <tr>

            <td><b>Needs Replacement</b></td>

            <td>{NeedsReplacement}</td>

        </tr>

        <tr>

            <td style="background-color: rgb(225, 225, 225);"><b>Date Installed</b></td>

            <td style="background-color: rgb(225, 225, 225);">{DateInstalled}</td>

        </tr>

        <tr>

            <td><b>Park</b></td>

            <td>{Park}</td>

        </tr>

        <tr>

            <td style="background-color: rgb(225, 225, 225);"><b>Notes</b></td>

            <td style="background-color: rgb(225, 225, 225);">{Notes}</td>

        </tr>

    </tbody>

</table>

I could definitely be overthinking this, but I tried to adapt the expression just to test it out with one of my own layers (this is a different layer than shown above, but you get the idea I think):

// Build an HTML table to display the summary of
// crimes by count and how many occurred at night
var cssGray = "style='background-color:#d6d6d6;'";
var cssRight = "style='text-align: right;'";
var cssCenter = "style='text-align: center;'";

var table = "<table style='width: 350px'>";


var i = 0;
for(var item in $feature){
 
  table += `<tr ${IIF( i % 2 != 0, cssGray, null )}>
    <td ${cssRight}>Cultivar</td>
    <td ${cssRight}>${$feature.Cultivar}</td>
  </tr>`;
  i++;
}
table += "</table>";

// Return the table as a text element
return {
  type: "text",
  text: table
};
 
And I get this:
 
ZachBodenner_2-1691073405323.png

 

0 Kudos
KenBuja
MVP Esteemed Contributor

A couple of things. Your code is looping through at the fields of the feature, but you're returning only the one attribute for Cultivar for each field. Also, you're arbitrarily setting the size of the table to 350 px, which is larger than the popup width. Use width=100%, which will make the table as big as the longest value and attribute. Try this instead (and please use the syntax button when adding code)

// Build an HTML table to display the summary of
// crimes by count and how many occurred at night
var cssGray = "style='background-color:#d6d6d6;'";
var cssRight = "style='text-align: right;'";
var cssCenter = "style='text-align: center;'";

var table = "<table style='width: 100%'>";

var i = 0;
for(var item in $feature){
 
  table += `<tr ${IIF( i % 2 != 0, cssGray, null )}>
    <td ${cssRight}>${item}</td>
    <td ${cssRight}>${$feature[item]}</td>
  </tr>`;
  i++;
}
table += "</table>";

// Return the table as a text element
return {
  type: "text",
  text: table
};

 

0 Kudos
ZachBodenner
MVP Regular Contributor

Okay so first of all that works great! Now, just a couple of last questions because I think I'm following for the most part:

1. the part of the code that says "For (var item in $feature){": in arcade, does item refer to table attributes specifically? It looks to me like it's just a variable name, but if that's the case which part of the code identifies "item" as being a list (array? I'm not sure) of attributes.

2. next, we call {$feature[item]}. If I had gotten there on my own, I think I would have tried {$feature.item}. What are the straight brackets doing for the code here?

3. also, what's the "`" for in the table portion?

PS thank you for the tip on the syntax button. I was looking for something like that in the expand toolbar menu, I just must have missed it. Will do in future.

 

0 Kudos
KenBuja
MVP Esteemed Contributor

1. Take a look at this page that talks about loops, and specifically, how looping through a feature works.

2. You have to use brackets when using a variable. Otherwise, Arcade interprets this as an actual field name.

3. Template literals use the back tick instead of single or double quotes.

Don't forget to click the "Mark as Solution" button for all the posts that helped you.

0 Kudos