Select to view content in your preferred language

URL with query parameter to open existing survey

2261
10
Jump to solution
09-18-2023 04:09 AM
TylerGraham2
Frequent Contributor

I'm beating my head against a wall here.  I'm working on integrating Field Maps and the Survey123 app to update our one of our data collection workflows. Monitors will enter a point, line, or polygon in Field Maps, click a link in the pop-up which will send them to the survey which is stored in a related table in the hosted feature service.

I've got an an Arcade script that will give a url to collect new monitoring notes and tie it to the feature by passing the feature GlobalID to a GUID field in the table if no existing record is found (which works great). What I'm struggling with is getting Survey123 to open an existing entry for editing. I'm trying to get it to find an existing monitoring note record by querying the GUID field for the related feature's GlobalID. The only query I can get to work on the table is the table's GlobalID field for an ID that I manually paste in: "q:GlobalID": '56bc00cb-4c8d-4e60-8553-a87dd98697cd', will open survey123 with that particular record opened for editing. Nothing else will work. When I click the link to edit a record, it just takes me to my inbox and shows all the entries. If I go too wild with trying to create a where= query shown in the Integrating with other apps page Survey123 gives me a code 400 error for invalid parameters.  

Here's the script:

var urlsource = 'arcgis-survey123://?';
var mon_note = FeatureSetByRelationshipName($feature, 'monitoring_notes',['point_guid'], false)
var mon_count = Count(mon_note)

if (mon_count==0) {
  var recmess = Text("Create New Record");
  var params = {
    itemID: 'c50d6e4981aa4919a06da9c37d121f95',
    action: 'collect',
    "field:point_guid": $feature["GlobalID"]
    };
} else {
  var recmess = Text("Edit Existing Monitoring Notes");
  var params = {
    itemID: 'c50d6e4981aa4919a06da9c37d121f95',
    action: 'edit',
    "q:point_guid": $feature["GlobalID"],  <--Here's where I'm stuck. This is what I want to do, query the point_guid field in the related table for a match to the parent feature's global ID.
    folder: 'inbox',
    update: 'true'
  };
}
var fullURL = urlsource + UrlEncode(params);
return {
  type: 'text',
  text: `<p> <a href="${fullURL}" target="_blank">${recmess}</a></p>`,
  //this property supports html tags
}
0 Kudos
1 Solution

Accepted Solutions
TylerGraham2
Frequent Contributor

I solved my own problem. The issue came from using the UrlEncode on the q:queryparameters, it would change 'where=' to 'where%3D' which appears to be the only part of the query that will cause the query to fail if it is encoded.  

q%3Awhere%3Dpoint_guid=%279462d173-fae1-42ca-a5ab-52afa8f417bb%27 <-- Does not work.

q%3Awhere=point_guid=%279462d173-fae1-42ca-a5ab-52afa8f417bb%27 <-- Works

I encoded the URL minus the query and attached it to the encoded url after setting it up as a Text formatted string, making sure to include the & .

var glid = Text("&q:where=point_guid=" + "%27" + $feature.GlobalID + "%27");
 

The order of all the parameters does not appear to matter, so attaching the query to the end of the encoded url seems to work without issue.  I did test it with apostrophes around $feature.GlobalID and it automatically converted them to %27, so I decided to use %27 in place of the apostrophes to prevent any conversion failures.  

Here is the full working script for reference:
var urlsource = 'arcgis-survey123://?';
var mon_note = FeatureSetByRelationshipName($feature, 'monitoring_notes',['point_guid'], false);
var mon_count = Count(mon_note);

if (mon_count==0) {
  var recmess = Text("Create New Record");
  var glid = '';
  var params = {
    itemID: 'c50d6e4981aa4919a06da9c37d121f95',
    action: 'collect',
    "field:point_guid": $feature["GlobalID"]
    };
} else {
  var recmess = Text("Edit Existing Monitoring Notes");
  var glid = Text("&q:where=point_guid=" + "%27" + $feature.GlobalID + "%27");
  var params = {
    action: 'edit',
    folder: 'inbox',
    itemID: 'c50d6e4981aa4919a06da9c37d121f95',
    update: 'true'
  };
}
var fullURL = urlsource + UrlEncode(params)+ glid;
return {
  type: 'text',
  text: `<p> <a href="${fullURL}" target="_blank">${recmess}</a></p>`,
  //this property supports html tags
}
 
 
 

View solution in original post

10 Replies
TylerGraham2
Frequent Contributor

I solved my own problem. The issue came from using the UrlEncode on the q:queryparameters, it would change 'where=' to 'where%3D' which appears to be the only part of the query that will cause the query to fail if it is encoded.  

q%3Awhere%3Dpoint_guid=%279462d173-fae1-42ca-a5ab-52afa8f417bb%27 <-- Does not work.

q%3Awhere=point_guid=%279462d173-fae1-42ca-a5ab-52afa8f417bb%27 <-- Works

I encoded the URL minus the query and attached it to the encoded url after setting it up as a Text formatted string, making sure to include the & .

var glid = Text("&q:where=point_guid=" + "%27" + $feature.GlobalID + "%27");
 

The order of all the parameters does not appear to matter, so attaching the query to the end of the encoded url seems to work without issue.  I did test it with apostrophes around $feature.GlobalID and it automatically converted them to %27, so I decided to use %27 in place of the apostrophes to prevent any conversion failures.  

Here is the full working script for reference:
var urlsource = 'arcgis-survey123://?';
var mon_note = FeatureSetByRelationshipName($feature, 'monitoring_notes',['point_guid'], false);
var mon_count = Count(mon_note);

if (mon_count==0) {
  var recmess = Text("Create New Record");
  var glid = '';
  var params = {
    itemID: 'c50d6e4981aa4919a06da9c37d121f95',
    action: 'collect',
    "field:point_guid": $feature["GlobalID"]
    };
} else {
  var recmess = Text("Edit Existing Monitoring Notes");
  var glid = Text("&q:where=point_guid=" + "%27" + $feature.GlobalID + "%27");
  var params = {
    action: 'edit',
    folder: 'inbox',
    itemID: 'c50d6e4981aa4919a06da9c37d121f95',
    update: 'true'
  };
}
var fullURL = urlsource + UrlEncode(params)+ glid;
return {
  type: 'text',
  text: `<p> <a href="${fullURL}" target="_blank">${recmess}</a></p>`,
  //this property supports html tags
}
 
 
 
RachaelMurtaugh
Frequent Contributor

I am trying to do this exact thing. I'm having a bit of a problem using your code. Can you clarify a couple things for me? I'm getting invalid parameters, and I'm not a fluent in Arcadce. I'm trying to understand your script and replace the pieces needed with my info. 

1. In one of the early lines "var mon_note = FeatureSetByRelationshipName($feature'monitoring_notes',['point_guid'], false);"  Is 'monitoring_notes' the name of the table related to your point feature? Then would that make 'point_guid' the GUID field, correct? What is the purpse of false? 

2. In this line "var glid = Text("&q:where=point_guid=" + "%27" + $feature.GlobalID + "%27");" Is the var glid a variable for a Global ID or GUID? If so, is the "where=point_guid" pointing to a GUID field in your related table and is "point_guid" the name of the field? 

0 Kudos
TylerGraham2
Frequent Contributor

Here's the break down on the Feature Set by Relationship Name function:

FeatureSet functions | ArcGIS Arcade | Esri Developer

'monitoring_notes' in mine is the relationship name between my point layer (parent) and the monitoring notes table (child) as set by the hosted feature service.  To find it, open your hosted feature service, click the link to view the REST services, then click on the parent layer. Scroll through the REST data until you see Relationships.

Screenshot 2025-09-26 092538.png

point_guid is the GUID field name I set in the child layer, yours will need to be whatever your GUID field name is. The False parameter is True/False for bringing the geometry in with it.  

 

For:

var glid = Text("&q:where=point_guid=" + "%27" + $feature.GlobalID + "%27");

This is a query where the attribute in the point_guid field (the GUID field in the child layer) matches the feature's GlobalID attribute.  You would need to change point_guid to whatever your guid field name is, but everything else should be able to be left unchanged.  Just check to make sure your parent layer's GlobalID field is formatted the same; e.g. globalid is different than GlobalID. If yours is different, change the arcade script to match.  

 

 

0 Kudos
RachaelMurtaugh
Frequent Contributor

Thankyou. One of my problems was I was using the wrong relationship name. I'm definitely close. Below is my script. GUID is the field name for my related table's GUID. When I use this as is, I can click the link, but it doesn't go anywhere. When I remove last 3 lines and replace the last one with 

return urlsource + UrlEncode(params)+ glid;    It will go to Survey 123, but I get an error code 400. Cannot Perform Query. Invalid query parameters.
 
Another kink in this might be a point may have several related records, how will it know which record I need it to open? (preferrably, the most recent or one with a field like Status = Needs Repair.)
 
 
 
var urlsource = 'arcgis-survey123://?';
var inspection = FeatureSetByRelationshipName($feature, 'SignalInspection',['GUID'], false);
var insp_count = Count(inspection);

if (insp_count==0) {
  var recmess = Text("Create New Record");
  var glid = '';
  var params = {
    itemID: 'b5ad40b0c8014d7c92715d1fb65a2de1',
    action: 'collect',
    "field:GUID": $feature["GlobalID"]
    };
}
else {
  var recmess = Text("Edit Existing Inspection");
  var glid = Text("&q:where=GUID=" + "%27" + $feature.GlobalID + "%27");
  var params = {
    action: 'edit',
    folder: 'inbox',
    itemID: 'b5ad40b0c8014d7c92715d1fb65a2de1',
    update: 'true'
  };
}
var fullURL = urlsource + UrlEncode(params)+ glid;
return {
  type: 'text',
  text: `<p> <a href="${fullURL}" target="_blank">${recmess}</a></p>`,
 
}
0 Kudos
TylerGraham2
Frequent Contributor

That error code 400 could be from a couple things.  The else section of the script is checking the inbox folder of the survey matches to the search criteria.  Make sure your inbox is enabled on the survey and the send folder is disabled.  Another thing is check your xlsform on the survey and make sure your repeat tables (related records) have the bind::esri:parameters column with query in it, that will allow it to search the repeats when you open an existing record in Survey123.  If you need to edit the repeats you need to also include allowUpdates=true.  Here's a link on how to set up Survey123 to view and edit existing records in the field app. 

Screenshot 2025-09-26 122722.png

Check out this video, specifically the arcade section. It is going to help a lot to understand the concept.  My features only have 1 related record per feature, so I didn't need to do any for loops for multiple related records.  

What your script is currently doing is if there are 0 related records to a feature it formats a link to create a new record that will be related to the feature. Else, if there are not 0 related records it formats a link to open survey123 and edit the record. However, this script only accounts for 1 related record and not multiple records being returned.  Since you say you might have multiple related records you'll need to use a for loop. 

Since you also might want the status or date you'll need to add those to the list in the FeatureSetByRelationshipName. So instead of ['GUID'] you'll want ['GUID', 'Status', 'Inspct_Date'] or whatever those field names actually are.  If you want to bring all fields in (a potential performance issue if there's a lot you could use ['*'] instead.  

This is untested, but conceptually what I would try first to make it work with multiple relates where the link is showing the Status field as the link text.  I moved var fullURL into the if and the else statement and then set  an output that should hopefully pass the urls on to the return section, so you should get a list of URLs.  If your Status field isn't exactly that change it in the list and the rec.Satus line to rec.whateveritactuallyis in the for loop.    

var urlsource = 'arcgis-survey123://?';
var inspection = FeatureSetByRelationshipName($feature, 'SignalInspection',['GUID','Status'], false);
var insp_count = Count(inspection);

if (insp_count==0) {
   var recmess = Text("Create New Record");
   var glid = '';
   var params = {
      itemID: 'b5ad40b0c8014d7c92715d1fb65a2de1',
      action: 'collect',
      "field:GUID": $feature["GlobalID"]
      };
   var fullURL = urlsource + UrlEncode(params)+ glid;
   output1 += text(fullURL)
   }
else {
   for (var rec in inspection){
      var recmess = rec.Status;
      var glid = Text("&q:where=GUID=" + "%27" + $feature.GlobalID + "%27");
      var params = {
      action: 'edit',
      folder: 'inbox',
      itemID: 'b5ad40b0c8014d7c92715d1fb65a2de1',
      update: 'true'
      };
   var fullURL = urlsource + UrlEncode(params)+ glid;
   output1 += text(fullURL)
   };
}
return {
   type: 'text',
   text: `<p> <a href="${output1}" target="_blank">${recmess}</a></p>`,
}

 

RachaelMurtaugh
Frequent Contributor

I think this is going to be too complicated for my skill level. I'm running into the problem now where my original script that I have for a different expression to submit inspections/maintenance is only opening the first survey already done. My though is because the bind:esri:parameters is set to query allow Updates=true. I think I'll just need to reevaluate the workflow for the crews. Thank you for all of your time. I so appreciate it. Love the ESRI community forums. 

 

0 Kudos
TylerGraham2
Frequent Contributor

Don't give up yet! If I'm stuck on something, I'll save my original work somewhere else and start a new script building and testing it piece by piece. Use that video above as a guide to return text and drop everything related to building links and just try to get it to return some attributes from the feature service for multiple related features.  Once you do that, build up the link parameters and keep passing them as text. Then work on assembling a full link as text.  Copy and paste into a browser to test if they work. Once you get the links working then work on formatting them as html.  It is daunting overall, but a lot less intimidating in small pieces, plus you'll learn a lot.  If you get stuck, start a new thread in the community and people will usually show up to help.

0 Kudos
RachaelMurtaugh
Frequent Contributor

Thank you for the encouragement. One thing I might try is having it pull the completed surveys from the Sent folder. I know they typically don't want you have a Sent and Inbox, but there is only one team, so they are never going to be trying to hit both folders at the same time. I like your idea of starting a new thread with the code I have. Thank you for sharing yours and for all of your help. 

0 Kudos
TylerGraham2
Frequent Contributor

You're welcome! FYI, there's a big difference between Sent and Inbox.  Sent is what was sent from a particular device and is static (meaning other updates to the record won't show in the Sent Folder). Think of the Sent folder as a receipt that you did something.  The Inbox is a query of the feature service for matching records to your search criteria. 

If you're having people do anything with existing data, you want to use the Inbox to make sure the data is accessible to your people.  

0 Kudos