Arcade Expressions to get Hyperlinks from Multiple Overlapping Polygons

2718
5
Jump to solution
08-25-2021 07:21 AM
JCGuarneri
Frequent Contributor

Hello, all. I've seen similar questions asked here, but none quite get at what I'm looking for. We maintain a bunch of plan area polygons that store a hyperlink to scanned construction plans. Currently, we access those plans just from the popup of the plan area. In any given area, for any given asset (water mains, for example), there may be multiple plans that are relevant. Currently, we have to cycle through all the plan popups to find the one we want, but it's been requested that I make it so we can click on an individual asset and see all the relevant plans.

I'm thinking something with Arcade would be the best bet at a solution that is performant, maintainable, and doesn't balloon our database size. However, I can only seem to get about 2/3 of the way there.

I have an expression that can return each link on it's own line, but it's hard to read and it doesn't automatically format as a link:

 

 

//get names and hyperlinks of intersecting plan features
var plans = Intersects($feature, FeatureSetByName($datastore,"Plan Area", ["PlanName","Hyperlink"]));
//create string to store hyperlinks and add links with lines in between
var linkList = '';
for (var p in plans){
    var linklist =  linklist + p.Hyperlink  + TextFormatting.Newline;
}
return linklist;

 

Which returns:

https://website.com/link1.pdf 
https://website.com/link2.pdf 
https://website.com/link3.pdf 

Since it's all in a single field, none of the URL text acts as a link. What I'd like to do is have all the plan names listed and formatted as hyperlinks to the corresponding plan document:

Plan 1->https://website.com/link1.pdf
Plan 2->https://website.com/link2.pdf 
Plan 3->https://website.com/link3.pdf 

Have I reached the limits of the popup's capabilities, or is there a key step I missed? Alternatively, is there a way to pass this info to Javascript API to build a popup in a map built that way?

Tags (2)
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

You have more or less exhausted the popup's capabilities.

The next step would be to return HTML:

<a href="https://website.com/link1.pdf">Plan 1</a>

You don't have to try that; it won't work, as HTML returned by an expression is encoded and thus won't be evaluated.

 

One possible soultion to this: Figure out a maximum of plans you will have to return. For each plan, create an expression for the name and an expression for the hyperlink:

// Which hyperlink will be returned? Start with 1, increase for each subsequent expression
var index = 1
// get hyperlinks of intersecting plan features
var plans = Intersects($feature, FeatureSetByName($datastore,"Plan Area", ["Hyperlink"], true))
// no intersecting plans or you already returned all hyperlinks in previous expressions
if(plans == null || Count(plans) < index) { 
  return ""
}
// return the specified hyperlink
var i = 1
for(var p in plans) {
  if(i == index) {
    return p.Hyperlink
  }
  i += 1
}

 

// Which name will be returned? Start with 1, increase for each subsequent expression
var index = 1
// get names of intersecting plan features
var plans = Intersects($feature, FeatureSetByName($datastore,"Plan Area", ["PlanName"], true))
// no intersecting plans or you already returned all names in previous expressions
if(plans == null || Count(plans) < index) { 
  return ""
}
// return the specified name
var i = 1
for(var p in plans) {
  if(i == index) {
    return p.PlanName
  }
  i += 1
}

 

Configure your popup, switch to HTML source and put in your links:

<a href="{expression/plan_link_1}" target="_blank">{expression/plan_name_1}</a><br/>
<a href="{expression/plan_link_2}" target="_blank">{expression/plan_name_2}</a><br/>
<a href="{expression/plan_link_3}" target="_blank">{expression/plan_name_3}</a><br/>
<!-- and so on -->

 

You could make it simpler by just doing the hyperlink expressions and returning them in the popup's attribute table, they should be formatted as links, I think. You won't have the plan names, though.


Have a great day!
Johannes

View solution in original post

5 Replies
berniejconnors
Frequent Contributor

Great question.  I am going to follow this thread for the answer.  Sorry I can't help.

0 Kudos
JohannesLindner
MVP Frequent Contributor

You have more or less exhausted the popup's capabilities.

The next step would be to return HTML:

<a href="https://website.com/link1.pdf">Plan 1</a>

You don't have to try that; it won't work, as HTML returned by an expression is encoded and thus won't be evaluated.

 

One possible soultion to this: Figure out a maximum of plans you will have to return. For each plan, create an expression for the name and an expression for the hyperlink:

// Which hyperlink will be returned? Start with 1, increase for each subsequent expression
var index = 1
// get hyperlinks of intersecting plan features
var plans = Intersects($feature, FeatureSetByName($datastore,"Plan Area", ["Hyperlink"], true))
// no intersecting plans or you already returned all hyperlinks in previous expressions
if(plans == null || Count(plans) < index) { 
  return ""
}
// return the specified hyperlink
var i = 1
for(var p in plans) {
  if(i == index) {
    return p.Hyperlink
  }
  i += 1
}

 

// Which name will be returned? Start with 1, increase for each subsequent expression
var index = 1
// get names of intersecting plan features
var plans = Intersects($feature, FeatureSetByName($datastore,"Plan Area", ["PlanName"], true))
// no intersecting plans or you already returned all names in previous expressions
if(plans == null || Count(plans) < index) { 
  return ""
}
// return the specified name
var i = 1
for(var p in plans) {
  if(i == index) {
    return p.PlanName
  }
  i += 1
}

 

Configure your popup, switch to HTML source and put in your links:

<a href="{expression/plan_link_1}" target="_blank">{expression/plan_name_1}</a><br/>
<a href="{expression/plan_link_2}" target="_blank">{expression/plan_name_2}</a><br/>
<a href="{expression/plan_link_3}" target="_blank">{expression/plan_name_3}</a><br/>
<!-- and so on -->

 

You could make it simpler by just doing the hyperlink expressions and returning them in the popup's attribute table, they should be formatted as links, I think. You won't have the plan names, though.


Have a great day!
Johannes
JCGuarneri
Frequent Contributor

Johannes, I'll have to try that out and report back. I'd considered that approach as an option, but hadn't gone down the rabbit hole yet. That's a nice bit of code you've got and I feel like that could work, depending on the max number of plans.

0 Kudos
JCGuarneri
Frequent Contributor

@JohannesLindner I'm just getting around to this again. I was able to use your sample code to get the intersecting plan areas, and create hyperlinks. In the new map viewer (and maybe the old one, too), you can actually get the link text without invoking the HTML editor (just put in {PlanName} in the text box, then adding the link to that text.

I also extended your solution a bit by pulling the plan date in and sorting the results on that field:

// Which name will be returned? Start with 1, increase for each subsequent expression
var index = 1
// get names of intersecting plan features
var plans = Intersects($feature, FeatureSetByName($datastore,"Plan Area", ["PlanName","InstallDate"], true))
// no intersecting plans or you already returned all names in previous expressions
var plans = OrderBy(plans, 'InstallDate DESC');
if(plans == null || Count(plans) < index) { 
  return ""
}
// return the specified name
var i = 1
for(var p in plans) {
  if(i == index) {
    return p.PlanName
  }
  i += 1
}
0 Kudos
JCGuarneri
Frequent Contributor

@JohannesLindner I wanted to update this post to reflect the newer, better option. With the Arcade Popup Element available in Enterprise 11+ and AGOL, I can now write one bit of code that will build a list of links flexibly and add as many or as few as there are intersecting:

 

var plans = Intersects($feature, FeatureSetByName($map,"Plan Area",['PlanName','Hyperlink','InstallDate']));
var sortedPlans = OrderBy(plans,"'InstallDate' Desc");
var planList = `<div style = "background:lightgray"><h3>Plan Links</h3>`;

for(var p in sortedPlans){
    if (IsEmpty(p.PlanName) || IsEmpty(p.Hyperlink)){
        planList += ``
    }
    else{
    planList += `<p><b><a href = "${p.Hyperlink}" style ="color:blue">${p.PlanName}</a></b></p>`;
}
}
planList += `</div>`
return { 
	type : 'text', 
	text : planList//this property supports html tags 
}

 

 

In addition to being more flexible, it's a lot cleaner and makes it easy to do some basic HTML formatting so it looks just how you want it. Here's the output:

JCGuarneri_0-1684953601587.png