Select to view content in your preferred language

Arcade pop ups - Can you return field lists for multiple records?

713
2
Jump to solution
08-12-2024 10:52 AM
Labels (1)
LisaMerkhoferXerces
New Contributor

Hi all! I am trying to create a custom pop up in Map Viewer with the Arcade content element that will return related records from another layer (there is no relationship class, I am just using a filter statement). My challenge is that the relationship is 1:M and I would like to have the pop up display data from more than one record as a field list (i.e. return type "fields", as opposed to text or a pop up string). 

Is it possible to return a field list type for more than one record in an arcade element? Here's the basic code I am using that just gets the first related record, how can I modify it to return all related records? Thanks in advance for your ideas!

This code is modified from: https://www.esri.com/arcgis-blog/products/arcgis-online/mapping/part-2-introducing-arcade-pop-up-con... 

//Get count sublayer
var CountTable = FeatureSetByPortalItem(Portal("[url]"),"[itemID]", 0, ['*'],false)

// Filter related features by using a common attribute
Expects($feature, '*');
var siteID = $feature.SiteID
var filterStatement = 'SiteID = @SiteID'

// Related features as a variable
var relatedData = Filter(CountTable, filterStatement)

//Sort relatedData by date - I'd like to not just use the first record here if possible
var relatedDataSorted = First(OrderBy(relatedData,'ObsDate'))

//Get a list of the fields in the counts table
var countFields = Schema(relatedDataSorted).fields;
//Console("list of fields "+countFields)

//define custom functions
//function to list the name of a field
function getNames(field){
  return field.name;
}
 
//function to collect field metadata info
function getFieldsMetaData() {
  var field_meta = {};
  for (var f in countFields) {
      field_meta[Lower(countFields[f].name)] = {
          "alias": countFields[f].alias,
          "domain":HasKey(countFields[f],"domain"),
          "fieldType": countFields[f].type,
          "name" : countFields[f].name
      }
  }
  return field_meta;
}
 
//applies some basic formatting for dates and domains
function formatField(fieldMetaData) {
    if (fieldMetaData.domain == true) {
        return DomainName(countFields, fieldMetaData.name)
    }
    if (fieldMetaData.fieldType == "esriFieldTypeDate") {
        return Text(countFields[fieldMetaData.name], 'MMM DD YYYY hh:mm')
    }
    return countFields[fieldMetaData.name]
}
 
//function to filter the counts fields to only ones we want to show in the pop up, including no fields with null values.
function filterValidFields(fieldName){
  // skip fields that are not needed, must be listed in lower case
  var skipNames = [
  "objectid",
  "siteid"
  ];
  return !includes(skipNames, lower(fieldName)) //&& !IsEmpty(relatedDataSorted[fieldName]) && !IsNan(relatedDataSorted[fieldName]);
}

//get a filtered list of fields to show in the pop up
var validFields = Filter(Map(countFields, getNames), filterValidFields);

//build the pop up table
var attributes = {};
var fieldInfos = [];
var fieldMetaInfo = getFieldsMetaData();

for (var f in validFields){
  var fieldName = validFields[f];//count fields
  var fieldMeta = fieldMetaInfo[Lower(fieldName)]//lowercase field name
  var fieldAlias = fieldMeta.alias
  Push(fieldInfos, { fieldName: fieldAlias})
  attributes[fieldAlias] = relatedDataSorted[fieldName]
}

return {
  type: "fields",
  fieldInfos: fieldInfos,
  attributes: attributes
};

 

0 Kudos
1 Solution

Accepted Solutions
jcarlson
MVP Esteemed Contributor

Not easily, no. An Arcade popup element will be limited to a single field list. You can put as many related records into your field list as you want, but they won't be separated in any way, so they'll all sort of bleed together.

The other issue is that your attributes object needs unique keys. As you loop through your related records, you would need a new field name for each record, and while that's doable, it's not going to look great.

Since the text output will honor HTML tags, you could build a table with HTML and assign the appropriate style / class tags to get the final result to render just like a Field List. This would give you the flexibility to do multiple records in a clear way, too.

- Josh Carlson
Kendall County GIS

View solution in original post

2 Replies
jcarlson
MVP Esteemed Contributor

Not easily, no. An Arcade popup element will be limited to a single field list. You can put as many related records into your field list as you want, but they won't be separated in any way, so they'll all sort of bleed together.

The other issue is that your attributes object needs unique keys. As you loop through your related records, you would need a new field name for each record, and while that's doable, it's not going to look great.

Since the text output will honor HTML tags, you could build a table with HTML and assign the appropriate style / class tags to get the final result to render just like a Field List. This would give you the flexibility to do multiple records in a clear way, too.

- Josh Carlson
Kendall County GIS
ColinBergmann
Occasional Contributor

I do this all the time! I've set up a script that a frequently re-use that shows all related records as a collapsible field list with attachments links at the end using HTML. I've included my script in case its useful for you. Just a note that my script also includes pulling up a survey123 edit link for each related record, but you can take this out if need be. I've also attached a screenshot to show you what the end result looks like.

var gid = $feature.GlobalID //Get feature GlobalID
var s123_itemid = 'xxxxxxxxxxxxxxxxxxxxxx' //Define edit s123 item id

//define HTML for related records output. NOTE: All text enclosed with '#' will be dynamically replaced with attribute values (e.g., #DESCRIPTOR#)
//define html details -> summary component
var detailstag = '<details><summary><b><font color="#797a7a">#DESCRIPTOR#</b></font><font size="2" color = "#797a7a"><em> (click to expand)</em></font></summary>'

//Define S123 edit link for each related record
var editlink = '<a target="_blank" rel="noopener noreferrer" href="http://survey123.arcgis.com/share/'+s123_itemid+'?mode=edit&globalId=#EDITGLOBALID#">&#9997;<i> Edit Record</i></a>'

//define html table header
var tableformat = '<figure class="table" style="width:100%;"><table style="-webkit-text-stroke-width:0px;background-color:rgb(255, 255, 255);border-collapse:collapse;box-sizing:inherit;color:rgb(50, 50, 50);font-family:&quot;Avenir Next&quot;, &quot;Helvetica Neue&quot;, helvetica, arial, sans-serif;font-size:14px;font-style:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-weight:400;letter-spacing:normal;line-height:1.3em;orphans:2;text-align:start;text-decoration-color:initial;text-decoration-style:initial;text-decoration-thickness:initial;text-transform:none;white-space:normal;widows:2;word-spacing:0px;"><tbody style="box-sizing:inherit;">'

//define html code for each table row
var row = '<tr style="background-color:#ROWCOLOR#;box-sizing:inherit;"><th style="border-right:3px solid rgba(0, 0, 0, 0.05);box-sizing:inherit;font-size:12px;font-weight:400;padding:0.5em 0.7em;text-align:left;vertical-align:top;width:50%;word-break:break-word;">#FIELDALIAS#</th><td style="box-sizing:inherit;font-size:12px;font-weight:400;padding:0.5em 0.7em;vertical-align:top;width:50%;word-break:break-word;">#FIELDVALUE#</td></tr>'

//define base url of attachment links. NOTE: attachment service url MUST be a map service, since feature services require a token
var attach_serv_url = 'https://utility.arcgis.com/usrsvcs/servers/xyzxyzxyzxyzxyz/rest/services/xyzxyz/xyzxyz/MapServer/10'
var attachbase = '<a href="'+attach_serv_url+'/#ATTOBJECTID#/attachments/#ATTID#"><i>#ATTNAME#</i></a>'               
                
var closingtag = '</tbody></table></figure>' //define first html closing tag
var closingtag2='</details><br>' //define second html closing tag
var oddrowcolor = 'rgba(76, 76, 76, 0.02)' //define odd table row color
var evenrowcolor = 'rgba(76, 76, 76, 0.1)' //deinfe even table row color



//define query for your related records
var query = "INSPECT_TYPE IN ('IDDE Dry Weather','IDDE Wet Weather','IDDE Catchment Investigation')"

//Pull related record table data, filter for inspection type, order by inspection date in descending order
var relatedrecords = OrderBy(Filter(FeatureSetByRelationshipName($feature, "Form"),query), 'DATEINSPECT DESC')

//fields you want displayed for the related records, in order. Format: [Raw field name, field display name/alias]
var fields = [['DATEINSPECT','Inspection Date'],
							['INSPECTOR','Inspector Name'],
							['INSP_AFFILITATION','Inspector Affiliation'],
							['INSPECT_TYPE','Type of Inspection'],
							['STRUCTUREFOUND','Structure Found'],
							['ACCESSIBLE','Structure Accessible for Sampling?'],
							['ACCESSNOTES','Accessibility Notes'],
							['RAIN_24HR','Rain (>0.1") in Last 24 Hours?'],
							['SEDIMENT','Level of Sediment Accumulation'],
							['SCOURPROTECT','Scour Protection Condition'],
							['CONDITION','Outfall Condition'],
							['NEEDS_SERVICE','Needs Repair'],
							['NEEDS_CLEANING','Needs Cleaning'],
							['FLOW','Flow Present?'],
							['STAINING','Staining'],
							['FLOATABLES','Floatables'],
							['ODOR','Odor'],
							['FOAMFILM','Sewage, Sheens, Scum'],
							['SEWAGE','Visual Evidence of Sewage?'],
							['FLOW_VOL','Flow Volume'],
							['COLOR','Color of Flow'],
							['CLARITY','Clarity of Flow'],
							['TEMPCELSIUS','Temperature (deg C)'],
							['CONDUCTIVITY','Conductivity (micro-Siemens/cm)'],
							['PH','pH'],
							['AMMONIA','Ammonia (mg/L)'],
							['CHLORINE','Chlorine (mg/L)'],
							['SURFACTANTS','Surfactants (mg/L)'],
							['SALINITY','Salinity (ppt)'],
							['DISOXYGEN','Dissolved Oxygen (mg/L)'],
							['LABSMPLCOLLECTED','Sample for Lab Collected?'],
							['ENTEROCOCCUS_TXT','Enterococcus (CFU/100mL)'],
							['ECOIL_TXT','E. coli (CFU/100mL)'],
							['LABSAMPLE1','1. Lab Sample Test'],
							['LABRESULTS1','1. Lab Sample Results'],
							['LABSAMPLE2','2. Lab Sample Test'],
							['LABRESULTS2','2. Lab Sample Results'],
							['LABSAMPLE3','3. Lab Sample Test'],
							['LABRESULTS3','3. Lab Sample Results'],
							['LABSAMPLE4','4. Lab Sample Test'],
							['LABRESULTS4','4. Lab Sample Results'],
							['LABSAMPLE5','5. Lab Sample Test'],
							['LABRESULTS5','5. Lab Sample Results'],
							['LABSAMPLE6','6. Lab Sample Test'],
							['LABRESULTS6','6. Lab Sample Results'],
							['LABSAMPLE7','7. Lab Sample Test'],
							['LABRESULTS7','7. Lab Sample Results'],
							['ADDTLPARAMETERS','Additional Parameters Screened'],
							['IDDECLASS','Illicit Outfall Classification'],
							['REASONILLICIT','Reason for Illicit Suspicion'],
							['NOTES','Notes']]

var outstr = '' //initialize output string to hold final html code

//iterate through related records
for (var record in relatedrecords)
{
	
	//define summary text for each related record
	outstr += Replace(detailstag,'#DESCRIPTOR#',Text(record.DATEINSPECT,'MM-DD-YYYY')+' '+record.INSPECT_TYPE+' Inspection') +Replace(editlink,'#EDITGLOBALID#',StandardizeGuid(record.GlobalID,'digits-hyphen'))+ '<br>' +tableformat
	
	var ct = 0 //initialize count to track which fields in related records display table are odd or even to alternate row colors

	//iterate through fields to be included in table for each related record
	for (var f in fields)
	{
		//alternate table row colors depending whether row number is odd or even
		if (ct % 2 == 0){
			var color = evenrowcolor
		}
		else{
			var color = oddrowcolor
		}

		//get field display/alias name
		var fname = fields[f][1]

		//check for coded value domains and translate codes to descriptions
		if(!isEmpty(Domain(record,fields[f][0])) && Domain(record,fields[f][0]).type != 'range')
		{
			//if field has coded value domain, get attribute value as domain description
			var fvalue = DomainName(record,fields[f][0])
		}
		else{var fvalue = record[fields[f][0]]} // otherwise, get raw field value

		//if field is date type, convert date value to formatted text
		if (TypeOf(fvalue) == 'Date')
		{
			fvalue = Text(fvalue,'MM-DD-YYYY')
		}

		//replace html row format with field display name, field value, and row color. Then add to out_str
		var this_row = Replace(Replace(Replace(row, '#FIELDALIAS#', fname),'#FIELDVALUE#',fvalue),'#ROWCOLOR#',color)
		outstr += this_row

		ct +=1 //increment row count
	}

	var attach = Attachments(record) //get feature attachments
	var att_txt = '' //intialize attachment link string

	//check if record has attachments
	if (Count(attach)>0)
	{
		//start attachment string
		att_txt += '<br><b>Attachments:</b><br>'

		//iterate over attachments
		for (var a in attach)
		{
			var id = Text(attach[a].id) //get attachment id
			var name = attach[a].name //get attchment file name

			//add attachment id to template attachment html string. add attachment name as link text
			att_txt += Replace(Replace(Replace(attachbase,'#ATTOBJECTID#',record.OBJECTID),'#ATTID#',id),'#ATTNAME#',name)
			att_txt += '<br>' //add new line between attachments
		}
		
	}
	outstr += closingtag //add first closing tag for related record attribute table
	outstr += att_txt //add attchment string
	outstr += closingtag2 //add second closing tag to close details html
}

if (isEmpty(outstr)){outstr = 'No Inspection Records'} //return message if no related records are found
return { 
	type : 'text', 
	text : outstr //this property supports html tags 
}

 

 

 
 
0 Kudos