How to not use a list item more than once.

5589
24
Jump to solution
02-27-2019 07:32 AM
DougBrowning
MVP Esteemed Contributor

I have a select one list in a repeat where I want to stop, or warn, a user if they pick an item more than once during the repeats.  This list is about 1,300 items.

I created a field that keeps a running list from my repeat

join(", ", ${SpeciesList})

I tried this constraint on the list  not(contains(${AllPlants}, ${SpeciesList}))  but it always triggers since it is in the list as soon as i pick it.

Is there a way to count the number of string occurrences?  Or remove it from the check somehow.

Thanks for any ideas

Tags (3)
1 Solution

Accepted Solutions
AndrewPadilla
Occasional Contributor

Thanks for your response @EvanR. Yes, I should have mentioned, I had placed 'myFunctions.js' in a scripts folder (I believe the extensions folder works the same). In the end I did get it to work. It was as simple as placing quotation marks around false in my constraint. I have attached a revised working example. JavaScript files cannot be added here. One would need to create a 'myFunctions.js' and use the following function and place it in a scripts folder with in the survey folder: 

function HasDups (myArray){

return new Set(myArray).size !== myArray.length;

}

 

View solution in original post

24 Replies
DougBrowning
MVP Esteemed Contributor

I got this to kinda work but it has issues.  What I do is take off the last 3 chars of the running list, thus breaking up that last value - which is then not found.

not(contains(substr(${AllPlants}, 0, string-length(${AllPlants}) - 3), ${SpeciesList}))

If you go down the repeat in order this works.  But this falls apart if you go backwards in a repeat and try and change a value.

What would be nice is a count of the number of substrings found.  so substr("XXXXX", "X") returns 5 not just true false.  Or a contains that returns the position the string was found would work also.

Thanks for any ideas.

NourSalam
New Contributor III

I have used this workaround for a very similar use case and found it very useful! I do hope the count of duplicates becomes possible at some point!

0 Kudos
EvanR
by
New Contributor III

Trying to implement your solution because I had problems with the JavaScript function. However, the question I'm trying to add this constraint to is a decimal type, which is causing issues. I eventually figured out how to calculate a version of my list of entries with the current entry removed (non-trivial). However, because Survey123 lists appear to be a string type at their core rather than a true list, any subsequent value that matches part of a previous entry will not be allowed. For example, if my list of entries is "1,1.5,3" and I try to enter 5, it won't allow it since 1.5 contains a 5. Any suggestions? All entries will be positive values that are divisible by 0.5.

For reference, here's the complicated formula I came up with that calculates a version of the entries list with the current entry removed: if(string-length(${InterceptList})=string-length(string(${PointDistance_m})),"",substr(${InterceptList},0,string-length(${InterceptList})-string-length(string(${PointDistance_m}))))

${InterceptList} is the raw list and ${PointDistance_m} is the question I'm trying to constrain. Have to coerce values to string, and the if statement was necessary because any time I was making an initial entry it would appear in the list (removal of the current entry only seemed to work for entries after the first).

0 Kudos
EvanR
by
New Contributor III

Think I may have solved it: I calculated a second version of the value in question by multiplying each entry by a constant and use THAT for the list and the duplicate check. I haven't yet tested it fully but it seems to work so far. First tried adding a constant, but that caused problems as well (e.g., if you add 0.3, 200, etc. to 16.5 and to 6.5 the latter will still be a substring of the former).

0 Kudos
AndrewPadilla
Occasional Contributor

I am looking for this solution as well. I attempted to use JavaScript as described in 

JavaScript funtions in Survey123 (https://community.esri.com/t5/arcgis-survey123-blog/extending-survey123-smart-forms-with-custom-js-f... but was unable to reproduce a working HasDups function in Survey123.  Has anyone else been able to successfully reproduce this example?  The constraint does not seem to register correctly. In the example below any fruits entered are an invalid selection with the constraint (${dups}=false).

AndrewPadilla_1-1614812922297.png

I attached an example file and script:

function HasDups (myArray){

return new Set(myArray).size !== myArray.length;

}

Thanks,

Andy

 

0 Kudos
EvanR
by
New Contributor III

Did you download repeats.js and place it in an "extensions" directory within your survey directory? You have to do that before you can call the script from your XLSForm. I was able to get it to work in Survey123 Connect once I figured out that step, but it didn't work when deployed to field tablets because of some restrictions on what exact flavors of AGOL etc. allow JavaScript, which was a bummer.

See here and also here. Let me know if that doesn't work for you and I'll take a closer look.

0 Kudos
AndrewPadilla
Occasional Contributor

Thanks for your response @EvanR. Yes, I should have mentioned, I had placed 'myFunctions.js' in a scripts folder (I believe the extensions folder works the same). In the end I did get it to work. It was as simple as placing quotation marks around false in my constraint. I have attached a revised working example. JavaScript files cannot be added here. One would need to create a 'myFunctions.js' and use the following function and place it in a scripts folder with in the survey folder: 

function HasDups (myArray){

return new Set(myArray).size !== myArray.length;

}

 

DougBrowning
MVP Esteemed Contributor

I’ve been mean to update this there’s been a couple new issues come up in the new three. 3.14 engine. I did get it working but it’s a little funky I’ll have to come back and post it I’m in the field now.  Basically you have to use once around the join so that you can go backwards. Then on your check add a comma in there on the check then it won’t find partial strings. And then the real funky one is join works differently on the very first element see you got a run a check for that.  ifI don’t post this next week remind me.

0 Kudos
ByronTsang-EPA
New Contributor

Just curious if you got this all working?  how did you implement the once() wrapper, and does that cause some angst when you go back into the repats and then return to the end? also how did you check for the join() behavior on the first repeat?

I'm working on a similar situation, and piecing together your recommendations posted here https://community.esri.com/t5/arcgis-survey123-questions/can-i-prevent-a-value-from-being-submitted/...  but curious if you've advanced your constraint calls to accomodate going back into older repeats

0 Kudos